Introduce RSInfo and its reader/extractor/writer.

This commit only adds files that implements RSInfo class and DOES
NOT switch to use it.

RSInfo defines the new file format to cache the metadata and
RS-specific information from the source bitcode.

It's the replacement of the old "MC cache" whose name is ambiguous
and some fields within that are deprecated after legacy JIT was
removed.

Reader of RSInfo reads information from the file we called "RS info
file." It will replace MCCacheReader.

Extractor of RSInfo extracts information from the metadata section of
the source bitcode. It will replace MetadataExtractor.

Writer of RSInfo serializes a RSInfo object to a file such that
we can load it quickly using RSInfo reader later. It will replace
MCCacheWriter.

RSInfo unifies the interfaces to get the RS-specific information
such as #rs_export_var supplied by the developers either from file
(RS info file) or from the source bitcode. Later commit will prove
that.

RSInfo uses signature ("\0rsinfo\n") which is different from the
old MC cache ("\0bcc").

The version (MCO_VERSION in bcc_mccache.h) is increased by 1 in this
commit since we remove res_type in MCO_Dependency. RSInfo inherits
the version number comes from old MC cache therefore its version
number starts with 3.
diff --git a/lib/ExecutionEngine/RSInfoReader.cpp b/lib/ExecutionEngine/RSInfoReader.cpp
new file mode 100644
index 0000000..a3eca5a
--- /dev/null
+++ b/lib/ExecutionEngine/RSInfoReader.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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.
+ */
+
+//===----------------------------------------------------------------------===//
+// This file implements RSInfo::ReadFromFile()
+//===----------------------------------------------------------------------===//
+
+#include "RSInfo.h"
+
+#include <new>
+
+#include <utils/FileMap.h>
+
+#include "DebugHelper.h"
+#include "InputFile.h"
+
+using namespace bcc;
+
+namespace {
+
+template<typename ItemType, typename ItemContainer>
+inline bool helper_read_list_item(const ItemType &pItem,
+                                  const RSInfo &pInfo,
+                                  ItemContainer &pResult);
+
+// Process DependencyTableItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::DependencyTableItem, RSInfo::DependencyTableTy>(
+    const rsinfo::DependencyTableItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::DependencyTableTy &pResult)
+{
+  const char *id = pInfo.getStringFromPool(pItem.id);
+  const uint8_t *sha1 =
+      reinterpret_cast<const uint8_t *>(pInfo.getStringFromPool(pItem.sha1));
+
+  if (id == NULL) {
+    ALOGE("Invalid string index %d for source id in RS dependenct table.",
+          pItem.id);
+    return false;
+  }
+
+  if (sha1 == NULL) {
+    ALOGE("Invalid string index %d for SHA-1 checksum in RS dependenct table.",
+          pItem.id);
+    return false;
+  }
+
+  pResult.push(std::make_pair(id, sha1));
+  return true;
+}
+
+// Process PragmaItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::PragmaItem, RSInfo::PragmaListTy>(
+    const rsinfo::PragmaItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::PragmaListTy &pResult)
+{
+  const char *key = pInfo.getStringFromPool(pItem.key);
+  const char *value =pInfo.getStringFromPool(pItem.value);
+
+  if (key == NULL) {
+    ALOGE("Invalid string index %d for key in RS pragma list.", pItem.key);
+    return false;
+  }
+
+  if (value == NULL) {
+    ALOGE("Invalid string index %d for value in RS pragma list.", pItem.value);
+    return false;
+  }
+
+  pResult.push(std::make_pair(key, value));
+  return true;
+}
+
+// Procee ObjectSlotItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::ObjectSlotItem, RSInfo::ObjectSlotListTy>(
+    const rsinfo::ObjectSlotItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::ObjectSlotListTy &pResult)
+{
+  pResult.push(pItem.slot);
+  return true;
+}
+
+// Procee ExportVarNameItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::ExportVarNameItem, RSInfo::ExportVarNameListTy>(
+    const rsinfo::ExportVarNameItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::ExportVarNameListTy &pResult)
+{
+  const char *name = pInfo.getStringFromPool(pItem.name);
+
+  if (name == NULL) {
+    ALOGE("Invalid string index %d for name in RS export vars.", pItem.name);
+    return false;
+  }
+
+  pResult.push(name);
+  return true;
+}
+
+// Procee ExportFuncNameItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::ExportFuncNameItem, RSInfo::ExportFuncNameListTy>(
+    const rsinfo::ExportFuncNameItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::ExportFuncNameListTy &pResult)
+{
+  const char *name = pInfo.getStringFromPool(pItem.name);
+
+  if (name == NULL) {
+    ALOGE("Invalid string index %d for name in RS export funcs.", pItem.name);
+    return false;
+  }
+
+  pResult.push(name);
+  return true;
+}
+
+// Procee ExportForeachFuncItem in the file
+template<> inline bool
+helper_read_list_item<rsinfo::ExportForeachFuncItem, RSInfo::ExportForeachFuncListTy>(
+    const rsinfo::ExportForeachFuncItem &pItem,
+    const RSInfo &pInfo,
+    RSInfo::ExportForeachFuncListTy &pResult)
+{
+  const char *name = pInfo.getStringFromPool(pItem.name);
+
+  if (name == NULL) {
+    ALOGE("Invalid string index %d for name in RS export foreachs.", pItem.name);
+    return false;
+  }
+
+  pResult.push(std::make_pair(name, pItem.signature));
+  return true;
+}
+
+template<typename ItemType, typename ItemContainer>
+inline bool helper_read_list(const uint8_t *pData,
+                             const RSInfo &pInfo,
+                             const rsinfo::ListHeader &pHeader,
+                             ItemContainer &pResult) {
+  const ItemType *item;
+
+  // Out-of-range exception has been checked.
+  for (uint32_t i = 0; i < pHeader.count; i++) {
+    item = reinterpret_cast<const ItemType *>(pData +
+                                              pHeader.offset +
+                                              i * pHeader.itemSize);
+    if (!helper_read_list_item<ItemType, ItemContainer>(*item, pInfo, pResult)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+} // end anonymous namespace
+
+RSInfo *RSInfo::ReadFromFile(InputFile &pInput,
+                             const RSScript::SourceDependencyListTy &pDeps) {
+  android::FileMap *map = NULL;
+  RSInfo *result = NULL;
+  const uint8_t *data;
+  const rsinfo::Header *header;
+  size_t filesize;
+  const char *input_filename = pInput.getName().c_str();
+  const off_t cur_input_offset = pInput.tell();
+
+  if (pInput.hasError()) {
+    ALOGE("Invalid RS info file %s! (%s)", input_filename,
+                                           pInput.getErrorMessage().c_str());
+    goto bail;
+  }
+
+  filesize = pInput.getSize();
+  if (pInput.hasError()) {
+    ALOGE("Failed to get the size of RS info file %s! (%s)",
+          input_filename, pInput.getErrorMessage().c_str());
+    goto bail;
+  }
+
+  // Create memory map for the file.
+  map = pInput.createMap(/* pOffset */cur_input_offset,
+                         /* pLength */filesize - cur_input_offset);
+  if (map == NULL) {
+    ALOGE("Failed to map RS info file %s to the memory! (%s)",
+          input_filename, pInput.getErrorMessage().c_str());
+    goto bail;
+  }
+
+  data = reinterpret_cast<const uint8_t *>(map->getDataPtr());
+
+  // Header starts at the beginning of the file.
+  header = reinterpret_cast<const rsinfo::Header *>(data);
+
+  // Check the magic.
+  if (::memcmp(header->magic, RSINFO_MAGIC, sizeof(header->magic)) != 0) {
+    ALOGV("Wrong magic found in the RS info file %s. Treat it as a dirty "
+          "cache.", input_filename);
+    goto bail;
+  }
+
+  // Check the version.
+  if (::memcmp(header->version,
+               RSINFO_VERSION,
+               sizeof((header->version)) != 0)) {
+    ALOGV("Mismatch the version of RS info file %s: (current) %s v.s. (file) "
+          "%s. Treat it as as a dirty cache.", input_filename, RSINFO_VERSION,
+          header->version);
+    goto bail;
+  }
+
+  // Check the size.
+  if ((header->headerSize != sizeof(rsinfo::Header)) ||
+      (header->dependencyTable.itemSize != sizeof(rsinfo::DependencyTableItem)) ||
+      (header->pragmaList.itemSize != sizeof(rsinfo::PragmaItem)) ||
+      (header->objectSlotList.itemSize != sizeof(rsinfo::ObjectSlotItem)) ||
+      (header->exportVarNameList.itemSize != sizeof(rsinfo::ExportVarNameItem)) ||
+      (header->exportFuncNameList.itemSize != sizeof(rsinfo::ExportFuncNameItem)) ||
+      (header->exportForeachFuncList.itemSize != sizeof(rsinfo::ExportForeachFuncItem))) {
+    ALOGW("Corrupted RS info file %s! (unexpected size found)", input_filename);
+    goto bail;
+  }
+
+  // Check the range.
+#define LIST_DATA_RANGE(_list_header) \
+  ((_list_header).offset + (_list_header).count * (_list_header).itemSize)
+  if (((header->headerSize + header->strPoolSize) > filesize) ||
+      (LIST_DATA_RANGE(header->dependencyTable) > filesize) ||
+      (LIST_DATA_RANGE(header->pragmaList) > filesize) ||
+      (LIST_DATA_RANGE(header->objectSlotList) > filesize) ||
+      (LIST_DATA_RANGE(header->exportVarNameList) > filesize) ||
+      (LIST_DATA_RANGE(header->exportFuncNameList) > filesize) ||
+      (LIST_DATA_RANGE(header->exportForeachFuncList) > filesize)) {
+    ALOGW("Corrupted RS info file %s! (data out of the range)", input_filename);
+    goto bail;
+  }
+#undef LIST_DATA_RANGE
+
+  // File seems ok, create result RSInfo object.
+  result = new (std::nothrow) RSInfo(header->strPoolSize);
+  if (result == NULL) {
+    ALOGE("Out of memory when create RSInfo object for %s!", input_filename);
+    goto bail;
+  }
+
+  // Make advice on our access pattern.
+  map->advise(android::FileMap::SEQUENTIAL);
+
+  // Copy the header.
+  ::memcpy(&result->mHeader, header, sizeof(rsinfo::Header));
+
+  if (header->strPoolSize > 0) {
+    // Copy the string pool. The string pool is immediately after the header at
+    // the offset header->headerSize.
+    if (result->mStringPool == NULL) {
+      ALOGE("Out of memory when allocate string pool for RS info file %s!",
+            input_filename);
+      goto bail;
+    }
+    ::memcpy(result->mStringPool, data + result->mHeader.headerSize,
+             result->mHeader.strPoolSize);
+  }
+
+  // Populate all the data to the result object.
+  if (!helper_read_list<rsinfo::DependencyTableItem, DependencyTableTy>
+        (data, *result, header->dependencyTable, result->mDependencyTable)) {
+    goto bail;
+  }
+
+  // Check dependency to see whether the cache is dirty or not.
+  if (!CheckDependency(*result, pInput.getName().c_str(), pDeps)) {
+    goto bail;
+  }
+
+  if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy>
+        (data, *result, header->pragmaList, result->mPragmas)) {
+    goto bail;
+  }
+
+  if (!helper_read_list<rsinfo::ObjectSlotItem, ObjectSlotListTy>
+        (data, *result, header->objectSlotList, result->mObjectSlots)) {
+    goto bail;
+  }
+
+  if (!helper_read_list<rsinfo::ExportVarNameItem, ExportVarNameListTy>
+        (data, *result, header->exportVarNameList, result->mExportVarNames)) {
+    goto bail;
+  }
+
+  if (!helper_read_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy>
+        (data, *result, header->exportFuncNameList, result->mExportFuncNames)) {
+    goto bail;
+  }
+
+  if (!helper_read_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy>
+        (data, *result, header->exportForeachFuncList, result->mExportForeachFuncs)) {
+    goto bail;
+  }
+
+  // Clean up.
+  map->release();
+
+  return result;
+
+bail:
+  if (map != NULL) {
+    map->release();
+  }
+
+  delete result;
+
+  return NULL;
+} // RSInfo::ReadFromFile