Add the CacheReader. (incomplete)
diff --git a/Android.mk b/Android.mk
index e799e70..22cf252 100644
--- a/Android.mk
+++ b/Android.mk
@@ -27,6 +27,7 @@
 
 libbcc_SRC_FILES := \
   lib/bcc/bcc.cpp \
+  lib/bcc/CacheReader.cpp \
   lib/bcc/CodeEmitter.cpp \
   lib/bcc/CodeMemoryManager.cpp \
   lib/bcc/Compiler.cpp \
@@ -35,6 +36,7 @@
   lib/bcc/Runtime.c \
   lib/bcc/Script.cpp \
   lib/bcc/ScriptCompiled.cpp \
+  lib/bcc/ScriptCached.cpp \
   helper/sha1.c
 
 # Shared library for target
diff --git a/include/bcc/bcc_cache.h b/include/bcc/bcc_cache.h
index 921e853..28c241d 100644
--- a/include/bcc/bcc_cache.h
+++ b/include/bcc/bcc_cache.h
@@ -19,97 +19,115 @@
 
 
 /* BCC Cache File Magic Word */
-#define OBCC_MAGIC       "bcc\n"
+#define OBCC_MAGIC "\0bcc"
 
 /* BCC Cache File Version, encoded in 4 bytes of ASCII */
-#define OBCC_MAGIC_VERS  "003\0"
+#define OBCC_VERSION "004\0"
 
 /* BCC Cache Header Structure */
-struct oBCCHeader {
-  uint8_t magic[4];             /* includes version number */
-  uint8_t magicVersion[4];
+struct OBCC_Header {
+  /* magic and version */
+  uint8_t magic[4];
+  uint8_t version[4];
 
-  long sourceWhen;
-  uint32_t rslibWhen;
-  uint32_t libRSWhen;
-  uint32_t libbccWhen;
+  /* machine-dependent integer type size */
+  uint8_t endianness;
+  uint8_t sizeof_off_t;
+  uint8_t sizeof_size_t;
+  uint8_t sizeof_ptr_t;
 
-  unsigned char sourceSHA1[20];
+  /* string pool section */
+  off_t str_pool_offset;
+  size_t str_pool_size;
 
-  uint32_t cachedCodeDataAddr;
-  uint32_t rootAddr;
-  uint32_t initAddr;
+  /* dependancy table */
+  off_t depend_tab_offset;
+  size_t depend_tab_size;
 
-  uint32_t libRSThreadable;     /* TODO: This is an hack. Should be fixed
-                                   in the long term. */
+  /* relocation table section */
+  off_t reloc_tab_offset;
+  size_t reloc_tab_size;
 
-  uint32_t relocOffset;         /* offset of reloc table. */
-  uint32_t relocCount;
-  uint32_t exportVarsOffset;    /* offset of export var table */
-  uint32_t exportVarsCount;
-  uint32_t exportFuncsOffset;   /* offset of export func table */
-  uint32_t exportFuncsCount;
-  uint32_t exportPragmasOffset; /* offset of export pragma table */
-  uint32_t exportPragmasCount;
-  uint32_t exportPragmasSize;   /* size of export pragma table (in bytes) */
+  /* export variable list section */
+  off_t export_var_list_offset;
+  size_t export_var_list_size;
 
-  uint32_t codeOffset;          /* offset of code: 64-bit alignment */
-  uint32_t codeSize;
-  uint32_t dataOffset;          /* offset of data section */
-  uint32_t dataSize;
+  /* export function list section */
+  off_t export_func_list_offset;
+  size_t export_func_list_size;
 
-  /* uint32_t flags; */         /* some info flags */
-  uint32_t checksum;            /* adler32 checksum covering deps/opt */
+  /* pragma list section */
+  off_t pragma_list_offset;
+  size_t pragma_list_size;
+
+  /* function table */
+  off_t func_table_offset;
+  size_t func_table_size;
+
+  /* context section */
+  off_t context_offset;
+  char *context_cached_addr;
+  uint32_t context_parity_checksum;
+
+  /* dirty hacks */
+  /* TODO: This is an hack. Should be removed. */
+  uint32_t libRS_threadable;
 };
 
-
-/* BCC Cache Relocation Entry */
-struct oBCCRelocEntry {
-  uint32_t relocType;           /* target instruction relocation type */
-  uint32_t relocOffset;         /* offset of hole (holeAddr - codeAddr) */
-  uint32_t cachedResultAddr;    /* address resolved at compile time */
-
-  oBCCRelocEntry(uint32_t ty, uintptr_t off, void *addr)
-    : relocType(ty),
-      relocOffset(static_cast<uint32_t>(off)),
-      cachedResultAddr(reinterpret_cast<uint32_t>(addr)) {
-  }
+struct OBCC_String {
+  size_t length; /* String length, without ending '\0' */
+  off_t offset; /* Note: Offset related to string_pool_offset. */
 };
 
-
-/* BCC Cache Pragma Entry */
-struct oBCCPragmaEntry {
-  uint32_t pragmaNameOffset;
-  uint32_t pragmaNameSize;
-  uint32_t pragmaValueOffset;
-  uint32_t pragmaValueSize;
+struct OBCC_StringPool {
+  size_t count;
+  struct OBCC_String list[];
 };
 
+struct OBCC_Dependancy {
+  size_t resource_strp_index;
+  char sha1[20];
+};
 
-/* BCC Cache Header Offset Table */
-/* TODO(logan): Deprecated.  Will remove this. */
-#define k_magic                 offsetof(oBCCHeader, magic)
-#define k_magicVersion          offsetof(oBCCHeader, magicVersion)
-#define k_sourceWhen            offsetof(oBCCHeader, sourceWhen)
-#define k_rslibWhen             offsetof(oBCCHeader, rslibWhen)
-#define k_libRSWhen             offsetof(oBCCHeader, libRSWhen)
-#define k_libbccWhen            offsetof(oBCCHeader, libbccWhen)
-#define k_cachedCodeDataAddr    offsetof(oBCCHeader, cachedCodeDataAddr)
-#define k_rootAddr              offsetof(oBCCHeader, rootAddr)
-#define k_initAddr              offsetof(oBCCHeader, initAddr)
-#define k_relocOffset           offsetof(oBCCHeader, relocOffset)
-#define k_relocCount            offsetof(oBCCHeader, relocCount)
-#define k_exportVarsOffset      offsetof(oBCCHeader, exportVarsOffset)
-#define k_exportVarsCount       offsetof(oBCCHeader, exportVarsCount)
-#define k_exportFuncsOffset     offsetof(oBCCHeader, exportFuncsOffset)
-#define k_exportFuncsCount      offsetof(oBCCHeader, exportFuncsCount)
-#define k_exportPragmasOffset   offsetof(oBCCHeader, exportPragmasOffset)
-#define k_exportPragmasCount    offsetof(oBCCHeader, exportPragmasCount)
-#define k_codeOffset            offsetof(oBCCHeader, codeOffset)
-#define k_codeSize              offsetof(oBCCHeader, codeSize)
-#define k_dataOffset            offsetof(oBCCHeader, dataOffset)
-#define k_dataSize              offsetof(oBCCHeader, dataSize)
-#define k_checksum              offsetof(oBCCHeader, checksum)
+struct OBCC_DependancyTable {
+  size_t count;
+  struct OBCC_Dependancy table[];
+};
+
+struct OBCC_RelocationTable {
+/* TODO: Implement relocation table. */
+};
+
+struct OBCC_ExportVarList {
+  size_t count;
+  void *cached_addr_list[];
+};
+
+struct OBCC_ExportFuncList {
+  size_t count;
+  void *cached_addr_list[];
+};
+
+struct OBCC_Pragma {
+  size_t key_strp_index;
+  size_t value_strp_index;
+};
+
+struct OBCC_PragmaList {
+  size_t count;
+  struct OBCC_Pragma list[];
+};
+
+struct OBCC_FuncInfo {
+  size_t name_strp_index;
+  size_t size;
+  void *cached_addr;
+};
+
+struct OBCC_FuncTable {
+  size_t count;
+  struct OBCC_FuncInfo table[];
+};
 
 
 #endif /* BCC_CACHE_H */
diff --git a/lib/bcc/CacheReader.cpp b/lib/bcc/CacheReader.cpp
new file mode 100644
index 0000000..949987e
--- /dev/null
+++ b/lib/bcc/CacheReader.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#include "CacheReader.h"
+
+#include "ContextManager.h"
+#include "FileHandle.h"
+#include "ScriptCached.h"
+
+#include <bcc/bcc_cache.h>
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <utility>
+#include <vector>
+
+#include <new>
+
+#include <string.h>
+
+using namespace std;
+
+
+namespace bcc {
+
+ScriptCached *CacheReader::readCacheFile(FileHandle *file) {
+  // Check file handle
+  if (!file || file->getFD() < 0) {
+    return NULL;
+  }
+
+  // Allocate ScriptCached object
+  mResult.reset(new (nothrow) ScriptCached(mpOwner));
+
+  if (!mResult) {
+    LOGE("Unable to allocate ScriptCached object.\n");
+    return NULL;
+  }
+
+  bool result = checkFileSize()
+             && readHeader()
+             && checkHeader()
+             && checkMachineIntType()
+             && checkSectionOffsetAndSize()
+             && readStringPool()
+             && checkStringPool()
+             && readDependencyTable()
+             && checkDependency()
+             && readExportVarList()
+             && readExportFuncList()
+             && readPragmaList()
+             && readFuncTable()
+             && readContext()
+             && checkContext()
+             //&& readRelocationTable()
+             //&& relocate()
+             ;
+
+
+  // TODO(logan): This is the hack for libRS.  Should be turned on
+  // before caching is ready to go.
+#if 0
+  // Check the cache file has __isThreadable or not.  If it is set,
+  // then we have to call mpSymbolLookupFn for __clearThreadable.
+  if (mHeader->libRSThreadable && mpSymbolLookupFn) {
+    mpSymbolLookupFn(mpSymbolLookupContext, "__clearThreadable");
+  }
+#endif
+
+  return result ? mResult.take() : NULL;
+}
+
+
+bool CacheReader::checkFileSize() {
+  struct stat stfile;
+  if (fstat(mFile->getFD(), &stfile) < 0) {
+    LOGE("Unable to stat cache file.\n");
+    return false;
+  }
+
+  mFileSize = stfile.st_size;
+
+  if (mFileSize < (off_t)sizeof(OBCC_Header) ||
+      mFileSize < (off_t)BCC_CONTEXT_SIZE) {
+    LOGE("Cache file is too small to be correct.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::readHeader() {
+  if (mFile->seek(0, SEEK_SET) != 0) {
+    LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
+    return false;
+  }
+
+  mHeader = (OBCC_Header *)malloc(sizeof(OBCC_Header));
+  if (!mHeader) {
+    LOGE("Unable to allocate for cache header.\n");
+    return false;
+  }
+
+  if (mFile->read(reinterpret_cast<char *>(mHeader), sizeof(OBCC_Header)) !=
+      (ssize_t)sizeof(OBCC_Header)) {
+    LOGE("Unable to read cache header.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::checkHeader() {
+  if (memcmp(mHeader->magic, OBCC_MAGIC, 4) != 0) {
+    LOGE("Bad magic word\n");
+    return false;
+  }
+
+  if (memcmp(mHeader->version, OBCC_VERSION, 4) != 0) {
+    LOGE("Bad oBCC version 0x%08x\n",
+         *reinterpret_cast<uint32_t *>(mHeader->version));
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::checkMachineIntType() {
+  uint32_t number = 0x00000001;
+
+  bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
+  if ((isLittleEndian && mHeader->endianness != 'e') ||
+      (!isLittleEndian && mHeader->endianness != 'E')) {
+    LOGE("Machine endianness mismatch.\n");
+    return false;
+  }
+
+  if ((unsigned int)mHeader->sizeof_off_t != sizeof(off_t) ||
+      (unsigned int)mHeader->sizeof_size_t != sizeof(size_t) ||
+      (unsigned int)mHeader->sizeof_ptr_t != sizeof(void *)) {
+    LOGE("Machine integer size mismatch.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::checkSectionOffsetAndSize() {
+#define CHECK_SECTION_OFFSET(NAME)                                          \
+  do {                                                                      \
+    off_t offset = mHeader-> NAME##_offset;                                 \
+    off_t size = (off_t)mHeader-> NAME##_size;                              \
+                                                                            \
+    if (mFileSize < offset || mFileSize < offset + size) {                  \
+      LOGE(#NAME " section overflow.\n");                                   \
+      return false;                                                         \
+    }                                                                       \
+                                                                            \
+    if (offset % sizeof(int) != 0) {                                        \
+      LOGE(#NAME " offset must aligned to %d.\n", 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
+
+  if (mFileSize < mHeader->context_offset ||
+      mFileSize < mHeader->context_offset + BCC_CONTEXT_SIZE) {
+    LOGE("context section overflow.\n");
+    return false;
+  }
+
+  long pagesize = sysconf(_SC_PAGESIZE);
+  if (mHeader->context_offset % pagesize != 0) {
+    LOGE("context offset must aligned to pagesize.\n");
+    return false;
+  }
+
+  // TODO(logan): Move this to some where else.
+  if ((uintptr_t)mHeader->context_cached_addr % pagesize != 0) {
+    LOGE("cached address is not aligned to pagesize.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::readStringPool() {
+  OBCC_StringPool *poolR = (OBCC_StringPool *)malloc(mHeader->str_pool_size);
+
+  if (!poolR) {
+    LOGE("Unable to allocate string pool.\n");
+    return false;
+  }
+
+  mResult->mpStringPoolRaw = poolR; // Managed by mResult from now on.
+
+  if (mFile->read(reinterpret_cast<char *>(poolR), mHeader->str_pool_size) !=
+      (ssize_t)mHeader->str_pool_size) {
+    LOGE("Unable to read string pool.\n");
+    return false;
+  }
+
+  vector<char const *> &pool = mResult->mStringPool;
+
+  for (size_t i = 0; i < poolR->count; ++i) {
+    char *str = reinterpret_cast<char *>(poolR) + poolR->list[i].offset;
+    pool.push_back(str);
+  }
+
+  return true;
+}
+
+
+bool CacheReader::checkStringPool() {
+  OBCC_StringPool *poolR = mResult->mpStringPoolRaw;
+  vector<char const *> &pool = mResult->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 CacheReader::readDependencyTable() {
+  // TODO(logan): Not finished.
+  return true;
+}
+
+
+bool CacheReader::checkDependency() {
+  // TODO(logan): Not finished.
+  return true;
+}
+
+bool CacheReader::readExportVarList() {
+  char *varList = (char *)malloc(mHeader->export_var_list_size);
+
+  if (!varList) {
+    LOGE("Unable to allocate exported variable list.\n");
+    return false;
+  }
+
+  mResult->mpExportVars = reinterpret_cast<OBCC_ExportVarList *>(varList);
+
+  if (mFile->seek(mHeader->export_var_list_offset, SEEK_SET) == -1) {
+    LOGE("Unable to seek to exported variable list section.\n");
+    return false;
+  }
+
+  if (mFile->read(varList, mHeader->export_var_list_size) !=
+      (ssize_t)mHeader->export_var_list_size) {
+    LOGE("Unable to read exported variable list.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::readExportFuncList() {
+  char *funcList = (char *)malloc(mHeader->export_func_list_size);
+
+  if (!funcList) {
+    LOGE("Unable to allocate exported function list.\n");
+    return false;
+  }
+
+  mResult->mpExportFuncs = reinterpret_cast<OBCC_ExportFuncList *>(funcList);
+
+  if (mFile->seek(mHeader->export_func_list_offset, SEEK_SET) == -1) {
+    LOGE("Unable to seek to exported function list section.\n");
+    return false;
+  }
+
+  if (mFile->read(funcList, mHeader->export_func_list_size) !=
+      (ssize_t)mHeader->export_func_list_size) {
+    LOGE("Unable to read exported function list.\n");
+    return false;
+  }
+
+  return true;
+}
+
+
+bool CacheReader::readPragmaList() {
+  OBCC_PragmaList *pragmaListRaw =
+    (OBCC_PragmaList *)malloc(mHeader->pragma_list_size);
+
+  if (!pragmaListRaw) {
+    LOGE("Unable to allocate pragma list.\n");
+    return false;
+  }
+
+  if (mFile->seek(mHeader->pragma_list_offset, SEEK_SET) == -1) {
+    LOGE("Unable to seek to pragma list section.\n");
+    return false;
+  }
+
+  if (mFile->read(reinterpret_cast<char *>(pragmaListRaw),
+                  mHeader->pragma_list_size) !=
+                              (ssize_t)mHeader->pragma_list_size) {
+    LOGE("Unable to read pragma list.\n");
+    return false;
+  }
+
+  vector<char const *> const &strPool = mResult->mStringPool;
+  ScriptCached::PragmaList &pragmas = mResult->mPragmas;
+
+  for (size_t i = 0; i < pragmaListRaw->count; ++i) {
+    OBCC_Pragma *pragma = &pragmaListRaw->list[i];
+    pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
+                                strPool[pragma->value_strp_index]));
+  }
+
+  return true;
+}
+
+
+bool CacheReader::readFuncTable() {
+  return false;
+}
+
+
+bool CacheReader::readContext() {
+  mResult->mContext = allocateContext(mHeader->context_cached_addr,
+                                      mFile->getFD(),
+                                      mHeader->context_offset);
+
+  if (!mResult->mContext) {
+    // Unable to allocate at cached address.  Give up.
+    return false;
+
+    // TODO(logan): If relocation is fixed, we should try to allocate the
+    // code in different location, and relocate the context.
+  }
+
+  return true;
+}
+
+
+bool CacheReader::checkContext() {
+  uint32_t sum = mHeader->context_parity_checksum;
+  uint32_t *ptr = reinterpret_cast<uint32_t *>(mResult->mContext);
+
+  for (size_t i = 0; i < BCC_CONTEXT_SIZE / sizeof(uint32_t); ++i) {
+    sum ^= *ptr++;
+  }
+
+  if (sum != 0) {
+    LOGE("Checksum check failed\n");
+    return false;
+  }
+
+  LOGI("Passed checksum even parity verification.\n");
+  return true;
+}
+
+
+bool CacheReader::readRelocationTable() {
+  // TODO(logan): Not finished.
+  return true;
+}
+
+
+bool CacheReader::relocate() {
+  // TODO(logan): Not finished.
+  return true;
+}
+
+
+} // namespace bcc
diff --git a/lib/bcc/CacheReader.h b/lib/bcc/CacheReader.h
new file mode 100644
index 0000000..48f1cd8
--- /dev/null
+++ b/lib/bcc/CacheReader.h
@@ -0,0 +1,84 @@
+/*
+ * 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_CACHEREADER_H
+#define BCC_CACHEREADER_H
+
+#include "ScriptCached.h"
+
+#include <llvm/ADT/OwningPtr.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include <stddef.h>
+
+struct OBCC_Header;
+
+namespace bcc {
+  class FileHandle;
+  class Script;
+
+  class CacheReader {
+  private:
+    Script *mpOwner;
+
+    FileHandle *mFile;
+    off_t mFileSize;
+
+    OBCC_Header *mHeader;
+
+    llvm::OwningPtr<ScriptCached> mResult;
+
+    std::map<std::string, char const *> mDependency;
+
+  public:
+    CacheReader(Script *owner)
+      : mpOwner(owner), mFile(NULL), mFileSize(0), mHeader(NULL) {
+    }
+
+    void addDependency(std::string const &resName, char const *sha1) {
+      mDependency.insert(std::make_pair(resName, sha1));
+    }
+
+    ScriptCached *readCacheFile(FileHandle *file);
+
+  private:
+    bool readHeader();
+    bool readStringPool();
+    bool readDependencyTable();
+    bool readExportVarList();
+    bool readExportFuncList();
+    bool readPragmaList();
+    bool readFuncTable();
+    bool readContext();
+    bool readRelocationTable();
+
+    bool checkFileSize();
+    bool checkHeader();
+    bool checkMachineIntType();
+    bool checkSectionOffsetAndSize();
+    bool checkStringPool();
+    bool checkDependency();
+    bool checkContext();
+
+    bool relocate();
+  };
+
+} // namespace bcc
+
+#endif // BCC_CACHEREADER_H
diff --git a/lib/bcc/Script.cpp b/lib/bcc/Script.cpp
index 6240ac7..48b75e0 100644
--- a/lib/bcc/Script.cpp
+++ b/lib/bcc/Script.cpp
@@ -19,7 +19,7 @@
 
 #include "Script.h"
 
-//#include "CacheReader.h"
+#include "CacheReader.h"
 //#include "CacheWriter.h"
 #include "FileHandle.h"
 #include "ScriptCompiled.h"
@@ -191,8 +191,7 @@
     return 1;
   }
 
-#if 0
-  CacheReader reader;
+  CacheReader reader(this);
 
   ScriptCached *cached = reader.readCacheFile(&file);
   if (!cached) {
@@ -201,9 +200,8 @@
 
   mCached = cached;
   mStatus = ScriptStatus::Cached;
-#endif
 
-  return 1;
+  return 0;
 }
 
 
@@ -331,7 +329,7 @@
   mCompiled->getFunctions(actualFunctionCount, maxFunctionCount, functions);
 }
 
-void const *Script::getContext() const {
+char const *Script::getContext() const {
   if (mStatus != ScriptStatus::Compiled) {
     //mErrorCode = BCC_INVALID_OPERATION;
     return NULL;
diff --git a/lib/bcc/Script.h b/lib/bcc/Script.h
index 008f918..c794c7b 100644
--- a/lib/bcc/Script.h
+++ b/lib/bcc/Script.h
@@ -33,7 +33,7 @@
     enum StatusType {
       Unknown,
       Compiled,
-      //Cached,
+      Cached,
     };
   }
 
diff --git a/lib/bcc/ScriptCached.cpp b/lib/bcc/ScriptCached.cpp
new file mode 100644
index 0000000..291bbc6
--- /dev/null
+++ b/lib/bcc/ScriptCached.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#include "ScriptCached.h"
+
+#include <bcc/bcc_cache.h>
+
+#include "ContextManager.h"
+#include "EmittedFuncInfo.h"
+
+namespace bcc {
+
+ScriptCached::~ScriptCached() {
+  // Deallocate the bcc script context
+  if (mContext) {
+    deallocateContext(mContext);
+  }
+
+  // Deallocate string pool, exported var list, exported func list
+  if (mpStringPoolRaw) { free(mpStringPoolRaw); }
+  if (mpExportVars) { free(mpExportVars); }
+  if (mpExportFuncs) { free(mpExportFuncs); }
+}
+
+void ScriptCached::getExportVars(BCCsizei *actualVarCount,
+                                 BCCsizei maxVarCount,
+                                 BCCvoid **vars) {
+  int varCount = static_cast<int>(mpExportVars->count);
+
+  if (actualVarCount)
+    *actualVarCount = varCount;
+  if (varCount > maxVarCount)
+    varCount = maxVarCount;
+  if (vars) {
+    void **ptr = mpExportVars->cached_addr_list;
+    for (int i = 0; i < varCount; i++) {
+      *vars++ = *ptr++;
+    }
+  }
+}
+
+
+void ScriptCached::getExportFuncs(BCCsizei *actualFuncCount,
+                                  BCCsizei maxFuncCount,
+                                  BCCvoid **funcs) {
+  int funcCount = static_cast<int>(mpExportFuncs->count);
+
+  if (actualFuncCount)
+    *actualFuncCount = funcCount;
+  if (funcCount > maxFuncCount)
+    funcCount = maxFuncCount;
+  if (funcs) {
+    void **ptr = mpExportFuncs->cached_addr_list;
+    for (int i = 0; i < funcCount; i++) {
+      *funcs++ = *ptr++;
+    }
+  }
+}
+
+
+void ScriptCached::getPragmas(BCCsizei *actualStringCount,
+                              BCCsizei maxStringCount,
+                              BCCchar **strings) {
+  int stringCount = static_cast<int>(mPragmas.size()) * 2;
+
+  if (actualStringCount)
+    *actualStringCount = stringCount;
+
+  if (stringCount > maxStringCount)
+    stringCount = maxStringCount;
+
+  if (strings) {
+    for (int i = 0; stringCount >= 2; stringCount -= 2, ++i) {
+      *strings++ = const_cast<BCCchar *>(mPragmas[i].first);
+      *strings++ = const_cast<BCCchar *>(mPragmas[i].second);
+    }
+  }
+}
+
+
+void *ScriptCached::lookup(const char *name) {
+  void *addr = NULL;
+
+  // TODO(logan): Not finished.
+  return addr;
+}
+
+
+void ScriptCached::getFunctions(BCCsizei *actualFunctionCount,
+                                BCCsizei maxFunctionCount,
+                                BCCchar **functions) {
+  LOGE("%s not implemented <<----------- WARNING\n", __func__);
+
+  if (actualFunctionCount) {
+    *actualFunctionCount = 0;
+  }
+}
+
+
+void ScriptCached::getFunctionBinary(BCCchar *funcname,
+                                     BCCvoid **base,
+                                     BCCsizei *length) {
+  LOGE("%s not implemented <<----------- WARNING\n", __func__);
+
+  if (base) {
+    *base = NULL;
+  }
+
+  if (length) {
+    *length = 0;
+  }
+}
+
+
+} // namespace bcc
diff --git a/lib/bcc/ScriptCached.h b/lib/bcc/ScriptCached.h
new file mode 100644
index 0000000..272e493
--- /dev/null
+++ b/lib/bcc/ScriptCached.h
@@ -0,0 +1,103 @@
+/*
+ * 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_SCRIPTCACHED_H
+#define BCC_SCRIPTCACHED_H
+
+#include <bcc/bcc.h>
+#include <bcc/bcc_cache.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;
+
+  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;
+
+    OBCC_ExportVarList *mpExportVars;
+    OBCC_ExportFuncList *mpExportFuncs;
+    PragmaList mPragmas;
+
+    FuncTable mFunctions;
+
+    char *mContext;
+
+    OBCC_StringPool *mpStringPoolRaw;
+    std::vector<char const *> mStringPool;
+
+  public:
+    ScriptCached(Script *owner)
+      : mpOwner(owner), mpExportVars(NULL), mpExportFuncs(NULL),
+        mContext(NULL), mpStringPoolRaw(NULL) {
+    }
+
+    ~ScriptCached();
+
+    void *lookup(const char *name);
+
+    void getExportVars(BCCsizei *actualVarCount,
+                       BCCsizei maxVarCount,
+                       BCCvoid **vars);
+
+    void getExportFuncs(BCCsizei *actualFuncCount,
+                        BCCsizei maxFuncCount,
+                        BCCvoid **funcs);
+
+    void getPragmas(BCCsizei *actualStringCount,
+                    BCCsizei maxStringCount,
+                    BCCchar **strings);
+
+    void getFunctions(BCCsizei *actualFunctionCount,
+                      BCCsizei maxFunctionCount,
+                      BCCchar **functions);
+
+    void getFunctionBinary(BCCchar *function,
+                           BCCvoid **base,
+                           BCCsizei *length);
+
+#if 0
+    void registerSymbolCallback(BCCSymbolLookupFn pFn, BCCvoid *pContext) {
+      mCompiler.registerSymbolCallback(pFn, pContext);
+    }
+#endif
+  };
+
+} // namespace bcc
+
+#endif // BCC_SCRIPTCACHED_H