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/include/bcc/bcc_mccache.h b/include/bcc/bcc_mccache.h
index a214831..64821e2 100644
--- a/include/bcc/bcc_mccache.h
+++ b/include/bcc/bcc_mccache.h
@@ -24,7 +24,7 @@
#define MCO_MAGIC "\0bcc"
/* BCC Cache File Version, encoded in 4 bytes of ASCII */
-#define MCO_VERSION "001\0"
+#define MCO_VERSION "002\0"
/* BCC Cache Header Structure */
struct MCO_Header {
@@ -89,14 +89,8 @@
struct MCO_String list[];
};
-enum MCO_ResourceType {
- BCC_APK_RESOURCE = 0,
- BCC_FILE_RESOURCE = 1,
-};
-
struct MCO_Dependency {
size_t res_name_strp_index;
- uint32_t res_type; /* BCC_APK_RESOURCE or BCC_FILE_RESOURCE */
unsigned char sha1[20];
};
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index c3566e5..430f872 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -34,6 +34,10 @@
MCCacheWriter.cpp \
MCCacheReader.cpp \
OutputFile.cpp \
+ RSInfo.cpp \
+ RSInfoExtractor.cpp \
+ RSInfoReader.cpp \
+ RSInfoWriter.cpp \
RSScript.cpp \
BCCRuntimeStub.c \
Script.cpp \
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
index 1a74ed3..dc4ba92 100644
--- a/lib/ExecutionEngine/MCCacheReader.cpp
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -289,17 +289,16 @@
}
vector<char const *> &strPool = mpResult->mStringPool;
- map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
+ 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;
- uint32_t depType = dep->second.first;
- unsigned char const *depSHA1 = dep->second.second;
+ 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;
+ //uint32_t depCachedType = depCached->res_type;
unsigned char const *depCachedSHA1 = depCached->sha1;
if (depName != depCachedName) {
@@ -326,11 +325,6 @@
return false;
}
-
- if (depType != depCachedType) {
- ALOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
- return false;
- }
}
return true;
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
index 39e438b..e2d10c5 100644
--- a/lib/ExecutionEngine/MCCacheReader.h
+++ b/lib/ExecutionEngine/MCCacheReader.h
@@ -50,8 +50,7 @@
llvm::OwningPtr<ScriptCached> mpResult;
- std::map<std::string,
- std::pair<uint32_t, unsigned char const *> > mDependencies;
+ std::map<std::string, unsigned char const *> mDependencies;
bool mIsContextSlotNotAvail;
@@ -68,11 +67,9 @@
~MCCacheReader();
- void addDependency(MCO_ResourceType resType,
- std::string const &resName,
+ void addDependency(std::string const &resName,
unsigned char const *sha1) {
- mDependencies.insert(std::make_pair(resName,
- std::make_pair((uint32_t)resType, sha1)));
+ mDependencies.insert(std::make_pair(resName, sha1));
}
ScriptCached *readCacheFile(InputFile &objFile, InputFile &infoFile, Script *s);
diff --git a/lib/ExecutionEngine/MCCacheWriter.cpp b/lib/ExecutionEngine/MCCacheWriter.cpp
index 7809234..c667c19 100644
--- a/lib/ExecutionEngine/MCCacheWriter.cpp
+++ b/lib/ExecutionEngine/MCCacheWriter.cpp
@@ -122,13 +122,12 @@
tab->count = mDependencies.size();
size_t i = 0;
- for (map<string, pair<uint32_t, unsigned char const *> >::iterator
+ 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());
- dep->res_type = I->second.first;
- memcpy(dep->sha1, I->second.second, 20);
+ memcpy(dep->sha1, I->second, 20);
}
return true;
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
index 1f462b3..47f1e40 100644
--- a/lib/ExecutionEngine/MCCacheWriter.h
+++ b/lib/ExecutionEngine/MCCacheWriter.h
@@ -36,8 +36,7 @@
std::vector<std::pair<char const *, size_t> > mStringPool;
- std::map<std::string,
- std::pair<uint32_t, unsigned char const *> > mDependencies;
+ std::map<std::string, unsigned char const *> mDependencies;
MCO_Header *mpHeaderSection;
MCO_StringPool *mpStringPoolSection;
@@ -65,11 +64,9 @@
bool writeCacheFile(OutputFile &objFile, OutputFile &infoFile,
RSScript *S, uint32_t libRS_threadable);
- void addDependency(MCO_ResourceType resType,
- std::string const &resName,
+ void addDependency(std::string const &resName,
unsigned char const *sha1) {
- mDependencies.insert(std::make_pair(resName,
- std::make_pair((uint32_t)resType, sha1)));
+ mDependencies.insert(std::make_pair(resName, sha1));
}
private:
diff --git a/lib/ExecutionEngine/RSInfo.cpp b/lib/ExecutionEngine/RSInfo.cpp
new file mode 100644
index 0000000..d351d36
--- /dev/null
+++ b/lib/ExecutionEngine/RSInfo.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#include "RSInfo.h"
+
+#include <cstring>
+#include <new>
+
+#include "FileBase.h"
+#include "DebugHelper.h"
+#include "Sha1Helper.h"
+
+using namespace bcc;
+
+const char RSInfo::LibBCCPath[] = "/system/lib/libbcc.so";
+const char RSInfo::LibRSPath[] = "/system/lib/libRS.so";
+uint8_t RSInfo::LibBCCSHA1[20];
+uint8_t RSInfo::LibRSSHA1[20];
+
+void RSInfo::LoadBuiltInSHA1Information() {
+ static bool loaded = false;
+
+ if (loaded) {
+ return;
+ }
+
+ // Read SHA-1 checksum of libbcc from hard-coded patch
+ // /system/lib/libbcc.so.sha1.
+ readSHA1(LibBCCSHA1, 20, "/system/lib/libbcc.so.sha1");
+
+ // Calculate the SHA-1 checksum of libRS.so.
+ calcFileSHA1(LibRSSHA1, LibRSPath);
+
+ loaded = true;
+
+ return;
+}
+
+android::String8 RSInfo::GetPath(const FileBase &pFile) {
+ android::String8 result(pFile.getName().c_str());
+ result.append(".info");
+ return result;
+}
+
+#define PRINT_DEPENDENCY(PREFIX, N, X) \
+ ALOGV("\t" PREFIX "Source name: %s, " \
+ "SHA-1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", \
+ (N), (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]);
+
+bool RSInfo::CheckDependency(const RSInfo &pInfo,
+ const char *pInputFilename,
+ const RSScript::SourceDependencyListTy &pDeps) {
+ // Built-in dependencies are libbcc.so and libRS.so.
+ static const unsigned NumBuiltInDependencies = 2;
+
+ LoadBuiltInSHA1Information();
+
+ if (pInfo.mDependencyTable.size() != (pDeps.size() + NumBuiltInDependencies)) {
+ ALOGD("Number of dependencies recorded mismatch (%lu v.s. %lu) in %s!",
+ static_cast<unsigned long>(pInfo.mDependencyTable.size()),
+ static_cast<unsigned long>(pDeps.size()), pInputFilename);
+ return false;
+ } else {
+ // Built-in dependencies always go first.
+ const std::pair<const char *, const uint8_t *> &cache_libbcc_dep =
+ pInfo.mDependencyTable[0];
+ const std::pair<const char *, const uint8_t *> &cache_libRS_dep =
+ pInfo.mDependencyTable[1];
+
+ // Check libbcc.so.
+ if (::memcmp(cache_libbcc_dep.second, LibBCCSHA1, 20) != 0) {
+ ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
+ LibBCCPath);
+ PRINT_DEPENDENCY("current - ", LibBCCPath, LibBCCSHA1);
+ PRINT_DEPENDENCY("cache - ", cache_libbcc_dep.first,
+ cache_libbcc_dep.second);
+ return false;
+ }
+
+ // Check libRS.so.
+ if (::memcmp(cache_libRS_dep.second, LibRSSHA1, 20) != 0) {
+ ALOGD("Cache %s is dirty due to %s has been updated.", pInputFilename,
+ LibRSPath);
+ PRINT_DEPENDENCY("current - ", LibRSPath, LibRSSHA1);
+ PRINT_DEPENDENCY("cache - ", cache_libRS_dep.first,
+ cache_libRS_dep.second);
+ return false;
+ }
+
+ for (unsigned i = 0; i < pDeps.size(); i++) {
+ const RSScript::SourceDependency &in_dep = *(pDeps[i]);
+ const std::pair<const char *, const uint8_t *> &cache_dep =
+ pInfo.mDependencyTable[i + NumBuiltInDependencies];
+
+ if ((::strncmp(in_dep.getSourceName().c_str(),
+ cache_dep.first,
+ in_dep.getSourceName().length()) != 0) ||
+ (::memcmp(in_dep.getSHA1Checksum(), cache_dep.second, 20) != 0)) {
+ ALOGD("Cache %s is dirty due to the source it dependends on has been "
+ "changed:", pInputFilename);
+ PRINT_DEPENDENCY("given - ", in_dep.getSourceName().c_str(),
+ in_dep.getSHA1Checksum());
+ PRINT_DEPENDENCY("cache - ", cache_dep.first, cache_dep.second);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+RSInfo::RSInfo(size_t pStringPoolSize) : mStringPool(NULL) {
+ ::memset(&mHeader, 0, sizeof(mHeader));
+
+ ::memcpy(mHeader.magic, RSINFO_MAGIC, sizeof(mHeader.magic));
+ ::memcpy(mHeader.version, RSINFO_VERSION, sizeof(mHeader.version));
+
+ mHeader.headerSize = sizeof(mHeader);
+
+ mHeader.dependencyTable.itemSize = sizeof(rsinfo::DependencyTableItem);
+ mHeader.pragmaList.itemSize = sizeof(rsinfo::PragmaItem);
+ mHeader.objectSlotList.itemSize = sizeof(rsinfo::ObjectSlotItem);
+ mHeader.exportVarNameList.itemSize = sizeof(rsinfo::ExportVarNameItem);
+ mHeader.exportFuncNameList.itemSize = sizeof(rsinfo::ExportFuncNameItem);
+ mHeader.exportForeachFuncList.itemSize = sizeof(rsinfo::ExportForeachFuncItem);
+
+ if (pStringPoolSize > 0) {
+ mHeader.strPoolSize = pStringPoolSize;
+ mStringPool = new (std::nothrow) char [ mHeader.strPoolSize ];
+ if (mStringPool == NULL) {
+ ALOGE("Out of memory when allocate memory for string pool in RSInfo "
+ "constructor (size: %u)!", mHeader.strPoolSize);
+ }
+ }
+}
+
+RSInfo::~RSInfo() {
+ delete [] mStringPool;
+}
+
+bool RSInfo::layout(off_t initial_offset) {
+ mHeader.dependencyTable.offset = initial_offset +
+ mHeader.headerSize +
+ mHeader.strPoolSize;
+ mHeader.dependencyTable.count = mDependencyTable.size();
+
+#define AFTER(_list) ((_list).offset + (_list).itemSize * (_list).count)
+ mHeader.pragmaList.offset = AFTER(mHeader.dependencyTable);
+ mHeader.pragmaList.count = mPragmas.size();
+
+ mHeader.objectSlotList.offset = AFTER(mHeader.pragmaList);
+ mHeader.objectSlotList.count = mObjectSlots.size();
+
+ mHeader.exportVarNameList.offset = AFTER(mHeader.objectSlotList);
+ mHeader.exportVarNameList.count = mExportVarNames.size();
+
+ mHeader.exportFuncNameList.offset = AFTER(mHeader.exportVarNameList);
+ mHeader.exportFuncNameList.count = mExportFuncNames.size();
+
+ mHeader.exportForeachFuncList.offset = AFTER(mHeader.exportFuncNameList);
+ mHeader.exportForeachFuncList.count = mExportForeachFuncs.size();
+#undef AFTER
+
+ return true;
+}
+
+void RSInfo::dump() const {
+ // Hide the codes to save the code size when debugging is disabled.
+#if !LOG_NDEBUG
+
+ // Dump header
+ ALOGV("RSInfo Header:");
+ ALOGV("\tIs threadable: %s", ((mHeader.isThreadable) ? "true" : "false"));
+ ALOGV("\tHeader size: %u", mHeader.headerSize);
+ ALOGV("\tString pool size: %u", mHeader.strPoolSize);
+
+#define DUMP_LIST_HEADER(_name, _header) do { \
+ ALOGV(_name ":"); \
+ ALOGV("\toffset: %u", (_header).offset); \
+ ALOGV("\t# of item: %u", (_header).count); \
+ ALOGV("\tsize of each item: %u", (_header).itemSize); \
+} while (false)
+ DUMP_LIST_HEADER("Dependency table", mHeader.dependencyTable);
+ for (DependencyTableTy::const_iterator dep_iter = mDependencyTable.begin(),
+ dep_end = mDependencyTable.end(); dep_iter != dep_end; dep_iter++) {
+ PRINT_DEPENDENCY("", dep_iter->first, dep_iter->second);
+ }
+
+ DUMP_LIST_HEADER("Pragma list", mHeader.pragmaList);
+ for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
+ pragma_end = mPragmas.end(); pragma_iter != pragma_end; pragma_iter++) {
+ ALOGV("\tkey: %s, value: %s", pragma_iter->first, pragma_iter->second);
+ }
+
+ DUMP_LIST_HEADER("RS object slots", mHeader.objectSlotList);
+ for (ObjectSlotListTy::const_iterator slot_iter = mObjectSlots.begin(),
+ slot_end = mObjectSlots.end(); slot_iter != slot_end; slot_iter++) {
+ ALOGV("slot: %u", *slot_iter);
+ }
+
+ DUMP_LIST_HEADER("RS export variables", mHeader.exportVarNameList);
+ for (ExportVarNameListTy::const_iterator var_iter = mExportVarNames.begin(),
+ var_end = mExportVarNames.end(); var_iter != var_end; var_iter++) {
+ ALOGV("name: %s", *var_iter);
+ }
+
+ DUMP_LIST_HEADER("RS export functions", mHeader.exportFuncNameList);
+ for (ExportFuncNameListTy::const_iterator func_iter = mExportFuncNames.begin(),
+ func_end = mExportFuncNames.end(); func_iter != func_end; func_iter++) {
+ ALOGV("name: %s", *func_iter);
+ }
+
+ DUMP_LIST_HEADER("RS foreach list", mHeader.exportForeachFuncList);
+ for (ExportForeachFuncListTy::const_iterator
+ foreach_iter = mExportForeachFuncs.begin(),
+ foreach_end = mExportForeachFuncs.end(); foreach_iter != foreach_end;
+ foreach_iter++) {
+ ALOGV("name: %s, signature: %05x", foreach_iter->first,
+ foreach_iter->second);
+ }
+#undef DUMP_LIST_HEADER
+
+#endif // LOG_NDEBUG
+ return;
+}
+
+const char *RSInfo::getStringFromPool(rsinfo::StringIndexTy pStrIdx) const {
+ // String pool uses direct indexing. Ensure that the pStrIdx is within the
+ // range.
+ if (pStrIdx >= mHeader.strPoolSize) {
+ ALOGE("String index #%u is out of range in string pool (size: %u)!",
+ pStrIdx, mHeader.strPoolSize);
+ return NULL;
+ }
+ return &mStringPool[ pStrIdx ];
+}
+
+rsinfo::StringIndexTy RSInfo::getStringIdxInPool(const char *pStr) const {
+ // Assume we are on the flat memory architecture (i.e., the memory space is
+ // continuous.)
+ if ((mStringPool + mHeader.strPoolSize) < pStr) {
+ ALOGE("String %s does not in the string pool!", pStr);
+ return rsinfo::gInvalidStringIndex;
+ }
+ return (pStr - mStringPool);
+}
+
+enum RSInfo::FloatPrecision RSInfo::getFloatPrecisionRequirement() const {
+ // Check to see if we have any FP precision-related pragmas.
+ static const char relaxed_pragma[] = "rs_fp_relaxed";
+ static const char imprecise_pragma[] = "rs_fp_imprecise";
+ bool relaxed_pragma_seen = false;
+
+ for (PragmaListTy::const_iterator pragma_iter = mPragmas.begin(),
+ pragma_end = mPragmas.end(); pragma_iter != pragma_end;
+ pragma_iter++) {
+ const char *pragma_key = pragma_iter->first;
+ if (::strcmp(pragma_key, relaxed_pragma) == 0) {
+ relaxed_pragma_seen = true;
+ } else if (::strcmp(pragma_key, imprecise_pragma) == 0) {
+ if (relaxed_pragma_seen) {
+ ALOGW("Multiple float precision pragmas specified!");
+ }
+ // Fast return when there's rs_fp_imprecise specified.
+ return Imprecise;
+ }
+ }
+
+ // Imprecise is selected over Relaxed precision.
+ // In the absence of both, we stick to the default Full precision.
+ if (relaxed_pragma_seen) {
+ return Relaxed;
+ } else {
+ return Full;
+ }
+ // unreachable
+}
diff --git a/lib/ExecutionEngine/RSInfo.h b/lib/ExecutionEngine/RSInfo.h
new file mode 100644
index 0000000..d69d15e
--- /dev/null
+++ b/lib/ExecutionEngine/RSInfo.h
@@ -0,0 +1,251 @@
+/*
+ * 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_INFO_FILE_H
+#define BCC_EXECUTION_ENGINE_RS_INFO_FILE_H
+
+#include <stdint.h>
+
+#include <utility>
+
+#include "RSScript.h"
+#include "DebugHelper.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace bcc {
+
+// Forward declarations
+class FileBase;
+class InputFile;
+class OutputFile;
+class Source;
+
+namespace rsinfo {
+
+/* RS info file magic */
+#define RSINFO_MAGIC "\0rsinfo\n"
+
+/* RS info file version, encoded in 4 bytes of ASCII */
+#define RSINFO_VERSION "003\0"
+
+struct __attribute__((packed)) ListHeader {
+ // The offset from the beginning of the file of data
+ uint32_t offset;
+ // Number of item in the list
+ uint32_t count;
+ // Size of each item
+ uint8_t itemSize;
+};
+
+/* RS info file header */
+struct __attribute__((packed)) Header {
+ // Magic versus version
+ uint8_t magic[8];
+ uint8_t version[4];
+
+ uint8_t isThreadable;
+ uint8_t hasDebugInformation;
+
+ uint16_t headerSize;
+
+ uint32_t strPoolSize;
+
+ struct ListHeader dependencyTable;
+ struct ListHeader pragmaList;
+ struct ListHeader objectSlotList;
+ struct ListHeader exportVarNameList;
+ struct ListHeader exportFuncNameList;
+ struct ListHeader exportForeachFuncList;
+};
+
+typedef uint32_t StringIndexTy;
+// Use value -1 as an invalid string index marker. No need to declare with
+// 'static' modifier since 'const' variable has internal linkage by default.
+const StringIndexTy gInvalidStringIndex = static_cast<StringIndexTy>(-1);
+
+struct __attribute__((packed)) DependencyTableItem {
+ StringIndexTy id;
+ // SHA-1 checksum is stored as a string in string pool (and has fixed-length
+ // 20 bytes)
+ StringIndexTy sha1;
+};
+
+struct __attribute__((packed)) PragmaItem {
+ // Pragma is a key-value pair.
+ StringIndexTy key;
+ StringIndexTy value;
+};
+
+struct __attribute__((packed)) ObjectSlotItem {
+ uint32_t slot;
+};
+
+struct __attribute__((packed)) ExportVarNameItem {
+ StringIndexTy name;
+};
+
+struct __attribute__((packed)) ExportFuncNameItem {
+ StringIndexTy name;
+};
+
+struct __attribute__((packed)) ExportForeachFuncItem {
+ StringIndexTy name;
+ uint32_t signature;
+};
+
+// Return the human-readable name of the given rsinfo::*Item in the template
+// parameter. This is for debugging and error message.
+template<typename Item>
+inline const char *GetItemTypeName();
+
+template<>
+inline const char *GetItemTypeName<DependencyTableItem>()
+{ return "rs dependency info"; }
+
+template<>
+inline const char *GetItemTypeName<PragmaItem>()
+{ return "rs pragma"; }
+
+template<>
+inline const char *GetItemTypeName<ObjectSlotItem>()
+{ return "rs object slot"; }
+
+template<>
+inline const char *GetItemTypeName<ExportVarNameItem>()
+{ return "rs export var"; }
+
+template<>
+inline const char *GetItemTypeName<ExportFuncNameItem>()
+{ return "rs export func"; }
+
+template<>
+inline const char *GetItemTypeName<ExportForeachFuncItem>()
+{ return "rs export foreach"; }
+
+} // end namespace rsinfo
+
+class RSInfo {
+public:
+ typedef android::Vector<std::pair<const char *,
+ const uint8_t *> > DependencyTableTy;
+ typedef android::Vector<std::pair<const char*, const char*> > PragmaListTy;
+ typedef android::Vector<uint32_t> ObjectSlotListTy;
+ typedef android::Vector<const char *> ExportVarNameListTy;
+ typedef android::Vector<const char *> ExportFuncNameListTy;
+ typedef android::Vector<std::pair<const char *,
+ uint32_t> > ExportForeachFuncListTy;
+
+public:
+ // Calculate or load the SHA-1 information of the built-in dependencies.
+ static void LoadBuiltInSHA1Information();
+
+ // Return the path of the RS info file corresponded to the given output
+ // executable file.
+ static android::String8 GetPath(const FileBase &pFile);
+
+ static const char LibBCCPath[];
+ static const char LibRSPath[];
+
+private:
+ // SHA-1 of the built-in dependencies. Will be initialized in
+ // LoadBuiltInSHA1Information().
+ static uint8_t LibBCCSHA1[20];
+ static uint8_t LibRSSHA1[20];
+
+ static bool CheckDependency(const RSInfo &pInfo,
+ const char *pInputFilename,
+ const RSScript::SourceDependencyListTy &pDeps);
+ static bool AddBuiltInDependencies(RSInfo &pInfo);
+
+ rsinfo::Header mHeader;
+
+ char *mStringPool;
+
+ // In most of the time, there're 4 source dependencies stored (libbcc.so,
+ // libRS.so, libclcore and the input bitcode itself.)
+ DependencyTableTy mDependencyTable;
+ PragmaListTy mPragmas;
+ ObjectSlotListTy mObjectSlots;
+ ExportVarNameListTy mExportVarNames;
+ ExportFuncNameListTy mExportFuncNames;
+ ExportForeachFuncListTy mExportForeachFuncs;
+
+ // Initialize an empty RSInfo with its size of string pool is pStringPoolSize.
+ RSInfo(size_t pStringPoolSize);
+
+ // layout() assigns value of offset in each ListHeader (i.e., it decides where
+ // data should go in the file.) It also updates fields other than offset to
+ // reflect the current RSInfo object states to mHeader.
+ bool layout(off_t initial_offset);
+
+public:
+ ~RSInfo();
+
+ // Implemented in RSInfoExtractor.cpp.
+ static RSInfo *ExtractFromSource(
+ const Source &pSource, const RSScript::SourceDependencyListTy &pDeps);
+
+ // Implemented in RSInfoReader.cpp.
+ static RSInfo *ReadFromFile(InputFile &pInput,
+ const RSScript::SourceDependencyListTy &pDeps);
+
+ // Implemneted in RSInfoWriter.cpp
+ bool write(OutputFile &pOutput);
+
+ void dump() const;
+
+ // const getter
+ inline bool isThreadable() const
+ { return mHeader.isThreadable; }
+ inline bool hasDebugInformation() const
+ { return mHeader.hasDebugInformation; }
+ inline const DependencyTableTy &getDependencyTable() const
+ { return mDependencyTable; }
+ inline const PragmaListTy &getPragmas() const
+ { return mPragmas; }
+ inline const ObjectSlotListTy &getObjectSlots() const
+ { return mObjectSlots; }
+ inline const ExportVarNameListTy &getExportVarNames() const
+ { return mExportVarNames; }
+ inline const ExportFuncNameListTy &getExportFuncNames() const
+ { return mExportFuncNames; }
+ inline const ExportForeachFuncListTy &getExportForeachFuncs() const
+ { return mExportForeachFuncs; }
+
+ const char *getStringFromPool(rsinfo::StringIndexTy pStrIdx) const;
+ rsinfo::StringIndexTy getStringIdxInPool(const char *pStr) const;
+
+ // setter
+ inline void setThreadable(bool pThreadable = true)
+ { mHeader.isThreadable = pThreadable; }
+
+public:
+ enum FloatPrecision {
+ Full,
+ Relaxed,
+ Imprecise,
+ };
+
+ // Return the minimal floating point precision required for the associated
+ // script.
+ enum FloatPrecision getFloatPrecisionRequirement() const;
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_RS_INFO_FILE_H
diff --git a/lib/ExecutionEngine/RSInfoExtractor.cpp b/lib/ExecutionEngine/RSInfoExtractor.cpp
new file mode 100644
index 0000000..6dbdc30
--- /dev/null
+++ b/lib/ExecutionEngine/RSInfoExtractor.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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::ExtractFromSource()
+//===----------------------------------------------------------------------===//
+#include "RSInfo.h"
+
+#include <llvm/Constants.h>
+#include <llvm/Metadata.h>
+#include <llvm/Module.h>
+
+#include "DebugHelper.h"
+#include "Source.h"
+
+using namespace bcc;
+
+namespace {
+
+// Name of metadata node where pragma info resides (should be synced with
+// slang.cpp)
+const llvm::StringRef pragma_metadata_name("#pragma");
+
+/*
+ * The following names should be synced with the one appeared in
+ * slang_rs_metadata.h.
+ */
+// Name of metadata node where exported variable names reside
+const llvm::StringRef export_var_metadata_name("#rs_export_var");
+
+// Name of metadata node where exported function names reside
+const llvm::StringRef export_func_metadata_name("#rs_export_func");
+
+// Name of metadata node where exported ForEach name information resides
+const llvm::StringRef export_foreach_name_metadata_name("#rs_export_foreach_name");
+
+// Name of metadata node where exported ForEach signature information resides
+const llvm::StringRef export_foreach_metadata_name("#rs_export_foreach");
+
+// Name of metadata node where RS object slot info resides (should be
+const llvm::StringRef object_slot_metadata_name("#rs_object_slots");
+
+inline llvm::StringRef getStringFromOperand(const llvm::Value *pString) {
+ if ((pString != NULL) && (pString->getValueID() == llvm::Value::MDStringVal)) {
+ return static_cast<const llvm::MDString *>(pString)->getString();
+ }
+ return llvm::StringRef();
+}
+
+template<size_t NumOperands>
+inline size_t getMetadataStringLength(const llvm::NamedMDNode *pMetadata) {
+ if (pMetadata == NULL) {
+ return 0;
+ }
+
+ size_t string_size = 0;
+ for (unsigned i = 0, e = pMetadata->getNumOperands(); i < e; i++) {
+ llvm::MDNode *node = pMetadata->getOperand(i);
+ if ((node != NULL) && (node->getNumOperands() >= NumOperands)) {
+ // Compiler try its best to unroll this loop since NumOperands is a
+ // template parameter (therefore the number of iteration can be determined
+ // at compile-time and it's usually small.)
+ for (unsigned j = 0; j < NumOperands; j++) {
+ llvm::StringRef s = getStringFromOperand(node->getOperand(j));
+ if (s.size() > 0) {
+ // +1 is for the null-terminator at the end of string.
+ string_size += (s.size() + 1);
+ }
+ }
+ }
+ }
+
+ return string_size;
+}
+
+// Write a string pString to the string pool pStringPool at offset pWriteStart.
+// Return the pointer the pString resides within the string pool.
+const char *writeString(const llvm::StringRef &pString, char *pStringPool,
+ off_t *pWriteStart) {
+ if (pString.empty()) {
+ return pStringPool;
+ }
+
+ char *pStringWriteStart = pStringPool + *pWriteStart;
+ // Copy the string.
+ ::memcpy(pStringWriteStart, pString.data(), pString.size());
+ // Write null-terminator at the end of the string.
+ pStringWriteStart[ pString.size() ] = '\0';
+ // Update pWriteStart.
+ *pWriteStart += (pString.size() + 1);
+
+ return pStringWriteStart;
+}
+
+bool writeDependency(const std::string &pSourceName, const uint8_t *pSHA1,
+ char *pStringPool, off_t *pWriteStart,
+ RSInfo::DependencyTableTy &pDepTable) {
+ const char *source_name = writeString(pSourceName, pStringPool, pWriteStart);
+
+ uint8_t *sha1 = reinterpret_cast<uint8_t *>(pStringPool + *pWriteStart);
+
+ // SHA-1 is special. It's 20-bytes long without null-terminator.
+ ::memcpy(sha1, pSHA1, 20);
+ // Record in the result RSInfo object.
+ pDepTable.push(std::make_pair(source_name, sha1));
+ // Update the string pool pointer.
+ *pWriteStart += 20;
+
+ return true;
+}
+
+} // end anonymous namespace
+
+RSInfo *RSInfo::ExtractFromSource(const Source &pSource,
+ const RSScript::SourceDependencyListTy &pDeps)
+{
+ const llvm::Module &module = pSource.getModule();
+ const char *module_name = module.getModuleIdentifier().c_str();
+
+ const llvm::NamedMDNode *pragma =
+ module.getNamedMetadata(pragma_metadata_name);
+ const llvm::NamedMDNode *export_var =
+ module.getNamedMetadata(export_var_metadata_name);
+ const llvm::NamedMDNode *export_func =
+ module.getNamedMetadata(export_func_metadata_name);
+ const llvm::NamedMDNode *export_foreach_name =
+ module.getNamedMetadata(export_foreach_name_metadata_name);
+ const llvm::NamedMDNode *export_foreach_signature =
+ module.getNamedMetadata(export_foreach_metadata_name);
+ const llvm::NamedMDNode *object_slots =
+ module.getNamedMetadata(object_slot_metadata_name);
+
+ // Always write a byte 0x0 at the beginning of the string pool.
+ size_t string_pool_size = 1;
+ off_t cur_string_pool_offset = 0;
+
+ RSInfo *result = NULL;
+
+ // Handle legacy case for pre-ICS bitcode that doesn't contain a metadata
+ // section for ForEach. We generate a full signature for a "root" function.
+ if ((export_foreach_name == NULL) || (export_foreach_signature == NULL)) {
+ export_foreach_name = NULL;
+ export_foreach_signature = NULL;
+ string_pool_size += 5; // insert "root\0" for #rs_export_foreach_name
+ }
+
+ string_pool_size += getMetadataStringLength<2>(pragma);
+ string_pool_size += getMetadataStringLength<1>(export_var);
+ string_pool_size += getMetadataStringLength<1>(export_func);
+ string_pool_size += getMetadataStringLength<1>(export_foreach_name);
+
+ // Don't forget to reserve the space for the dependency informationin string
+ // pool.
+ string_pool_size += ::strlen(LibBCCPath) + 1 + 20;
+ string_pool_size += ::strlen(LibRSPath) + 1 + 20;
+ for (unsigned i = 0, e = pDeps.size(); i != e; i++) {
+ const RSScript::SourceDependency *source_dep = pDeps[i];
+ if (source_dep != NULL) {
+ // +1 for null-terminator
+ string_pool_size += source_dep->getSourceName().length() + 1;
+ // +20 for SHA-1 checksum
+ string_pool_size += 20;
+ }
+ }
+
+ // Allocate result object
+ result = new (std::nothrow) RSInfo(string_pool_size);
+ if (result == NULL) {
+ ALOGE("Out of memory when create RSInfo object for %s!", module_name);
+ goto bail;
+ }
+
+ // Check string pool.
+ if (result->mStringPool == NULL) {
+ ALOGE("Out of memory when allocate string pool in RSInfo object for %s!",
+ module_name);
+ goto bail;
+ }
+
+ // First byte of string pool should be an empty string
+ result->mStringPool[ cur_string_pool_offset++ ] = '\0';
+
+ // Populate all the strings and data.
+#define FOR_EACH_NODE_IN(_metadata, _node) \
+ for (unsigned i = 0, e = (_metadata)->getNumOperands(); i != e; i++) \
+ if (((_node) = (_metadata)->getOperand(i)) != NULL)
+ //===--------------------------------------------------------------------===//
+ // #pragma
+ //===--------------------------------------------------------------------===//
+ // Pragma is actually a key-value pair. The value can be an empty string while
+ // the key cannot.
+ if (pragma != NULL) {
+ llvm::MDNode *node;
+ FOR_EACH_NODE_IN(pragma, node) {
+ llvm::StringRef key = getStringFromOperand(node->getOperand(0));
+ llvm::StringRef val = getStringFromOperand(node->getOperand(1));
+ if (key.empty()) {
+ ALOGW("%s contains pragma metadata with empty key (skip)!",
+ module_name);
+ } else {
+ result->mPragmas.push(std::make_pair(
+ writeString(key, result->mStringPool, &cur_string_pool_offset),
+ writeString(val, result->mStringPool, &cur_string_pool_offset)));
+ } // key.empty()
+ } // FOR_EACH_NODE_IN
+ } // pragma != NULL
+
+ //===--------------------------------------------------------------------===//
+ // #rs_export_var
+ //===--------------------------------------------------------------------===//
+ if (export_var != NULL) {
+ llvm::MDNode *node;
+ FOR_EACH_NODE_IN(export_var, node) {
+ llvm::StringRef name = getStringFromOperand(node->getOperand(0));
+ if (name.empty()) {
+ ALOGW("%s contains empty entry in #rs_export_var metadata (skip)!",
+ module_name);
+ } else {
+ result->mExportVarNames.push(
+ writeString(name, result->mStringPool, &cur_string_pool_offset));
+ }
+ }
+ }
+
+ //===--------------------------------------------------------------------===//
+ // #rs_export_func
+ //===--------------------------------------------------------------------===//
+ if (export_func != NULL) {
+ llvm::MDNode *node;
+ FOR_EACH_NODE_IN(export_func, node) {
+ llvm::StringRef name = getStringFromOperand(node->getOperand(0));
+ if (name.empty()) {
+ ALOGW("%s contains empty entry in #rs_export_func metadata (skip)!",
+ module_name);
+ } else {
+ result->mExportFuncNames.push(
+ writeString(name, result->mStringPool, &cur_string_pool_offset));
+ }
+ }
+ }
+
+ //===--------------------------------------------------------------------===//
+ // #rs_export_foreach and #rs_export_foreach_name
+ //===--------------------------------------------------------------------===//
+ // It's a little bit complicated to deal with #rs_export_foreach (the
+ // signature of foreach-able function) and #rs_export_foreach_name (the name
+ // of function which is foreach-able). We have to maintain a legacy case:
+ //
+ // In pre-ICS bitcode, forEach feature only supports non-graphic root()
+ // function and only one signature corresponded to that non-graphic root()
+ // was written to the #rs_export_foreach metadata section. There's no
+ // #rs_export_foreach_name metadata section.
+ //
+ // Currently, not only non-graphic root() is supported but also other
+ // functions that are exportable. Therefore, a new metadata section
+ // #rs_export_foreach_name is added to specify which functions are
+ // for-eachable. In this case, #rs_export_foreach (the function name) and
+ // #rs_export_foreach metadata (the signature) is one-to-one mapping among
+ // their entries.
+ if ((export_foreach_name != NULL) && (export_foreach_signature != NULL)) {
+ unsigned num_foreach_function;
+
+ // Should be one-to-one mapping.
+ if (export_foreach_name->getNumOperands() !=
+ export_foreach_signature->getNumOperands()) {
+ ALOGE("Mismatch number of foreach-able function names (%u) in "
+ "#rs_export_foreach_name and number of signatures (%u) "
+ "in %s!", export_foreach_name->getNumOperands(),
+ export_foreach_signature->getNumOperands(), module_name);
+ goto bail;
+ }
+
+ num_foreach_function = export_foreach_name->getNumOperands();
+ for (unsigned i = 0; i < num_foreach_function; i++) {
+ llvm::MDNode *name_node = export_foreach_name->getOperand(i);
+ llvm::MDNode *signature_node = export_foreach_signature->getOperand(i);
+
+ llvm::StringRef name, signature_string;
+ if (name_node != NULL) {
+ name = getStringFromOperand(name_node->getOperand(0));
+ }
+ if (signature_node != NULL) {
+ signature_string = getStringFromOperand(signature_node->getOperand(0));
+ }
+
+ if (!name.empty() && !signature_string.empty()) {
+ // Both name_node and signature_node are not NULL nodes.
+ uint32_t signature;
+ if (signature_string.getAsInteger(10, signature)) {
+ ALOGE("Non-integer signature value '%s' for function %s found in %s!",
+ signature_string.str().c_str(), name.str().c_str(), module_name);
+ goto bail;
+ }
+ result->mExportForeachFuncs.push(std::make_pair(
+ writeString(name, result->mStringPool, &cur_string_pool_offset),
+ signature));
+ } else {
+ // One or both of the name and signature value are empty. It's safe only
+ // if both of them are empty.
+ if (name.empty() && signature_string.empty()) {
+ ALOGW("Entries #%u at #rs_export_foreach_name and #rs_export_foreach"
+ " are both NULL in %s! (skip)", i, module_name);
+ continue;
+ } else {
+ ALOGE("Entries #%u at %s is NULL in %s! (skip)", i,
+ (name.empty() ? "#rs_export_foreach_name" :
+ "#rs_export_foreach"), module_name);
+ goto bail;
+ }
+ }
+ } // end for
+ } else {
+ // To handle the legacy case, we generate a full signature for a "root"
+ // function which means that we need to set the bottom 5 bits (0x1f) in the
+ // mask.
+ result->mExportForeachFuncs.push(std::make_pair(
+ writeString(llvm::StringRef("root"), result->mStringPool,
+ &cur_string_pool_offset), 0x1f));
+ }
+
+ //===--------------------------------------------------------------------===//
+ // #rs_object_slots
+ //===--------------------------------------------------------------------===//
+ if (object_slots != NULL) {
+ llvm::MDNode *node;
+ FOR_EACH_NODE_IN(object_slots, node) {
+ llvm::StringRef val = getStringFromOperand(node->getOperand(0));
+ if (val.empty()) {
+ ALOGW("%s contains empty entry in #rs_object_slots (skip)!",
+ module.getModuleIdentifier().c_str());
+ } else {
+ uint32_t slot;
+ if (val.getAsInteger(10, slot)) {
+ ALOGE("Non-integer object slot value '%s' in %s!", val.str().c_str(),
+ module.getModuleIdentifier().c_str());
+ goto bail;
+ }
+ }
+ }
+ }
+#undef FOR_EACH_NODE_IN
+
+ //===--------------------------------------------------------------------===//
+ // Record built-in dependency information.
+ //===--------------------------------------------------------------------===//
+ LoadBuiltInSHA1Information();
+
+ if (!writeDependency(LibBCCPath, LibBCCSHA1,
+ result->mStringPool, &cur_string_pool_offset,
+ result->mDependencyTable)) {
+ goto bail;
+ }
+
+ if (!writeDependency(LibRSPath, LibRSSHA1,
+ result->mStringPool, &cur_string_pool_offset,
+ result->mDependencyTable)) {
+ goto bail;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Record dependency information.
+ //===--------------------------------------------------------------------===//
+ for (unsigned i = 0, e = pDeps.size(); i != e; i++) {
+ const RSScript::SourceDependency *source_dep = pDeps[i];
+ if (source_dep != NULL) {
+ if (!writeDependency(source_dep->getSourceName(),
+ source_dep->getSHA1Checksum(),
+ result->mStringPool, &cur_string_pool_offset,
+ result->mDependencyTable)) {
+ goto bail;
+ }
+ }
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Determine whether the bitcode contains debug information
+ //===--------------------------------------------------------------------===//
+ // The root context of the debug information in the bitcode is put under
+ // the metadata named "llvm.dbg.cu".
+ result->mHeader.hasDebugInformation =
+ static_cast<uint8_t>(module.getNamedMetadata("llvm.dbg.cu") != NULL);
+
+ assert((cur_string_pool_offset == string_pool_size) &&
+ "Unexpected string pool size!");
+
+ return result;
+
+bail:
+ delete result;
+ return NULL;
+}
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
diff --git a/lib/ExecutionEngine/RSInfoWriter.cpp b/lib/ExecutionEngine/RSInfoWriter.cpp
new file mode 100644
index 0000000..d54fb41
--- /dev/null
+++ b/lib/ExecutionEngine/RSInfoWriter.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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::write()
+//===----------------------------------------------------------------------===//
+
+#include "RSInfo.h"
+
+#include "DebugHelper.h"
+#include "OutputFile.h"
+
+using namespace bcc;
+
+namespace {
+
+template<typename ItemType, typename ItemContainer> inline bool
+helper_adapt_list_item(ItemType &pResult, const RSInfo &pInfo,
+ const typename ItemContainer::const_iterator &pItem);
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::DependencyTableItem, RSInfo::DependencyTableTy>(
+ rsinfo::DependencyTableItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::DependencyTableTy::const_iterator &pItem) {
+ pResult.id = pInfo.getStringIdxInPool(pItem->first);
+ pResult.sha1 =
+ pInfo.getStringIdxInPool(reinterpret_cast<const char *>(pItem->second));
+
+ if (pResult.id == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS dependency table contains invalid source id string '%s'.",
+ pItem->first);
+ return false;
+ }
+
+ if (pResult.sha1 == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS dependency table contains invalid SHA-1 checksum string in '%s'.",
+ pItem->first);
+ return false;
+ }
+
+ return true;
+}
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::PragmaItem, RSInfo::PragmaListTy>(
+ rsinfo::PragmaItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::PragmaListTy::const_iterator &pItem) {
+ pResult.key = pInfo.getStringIdxInPool(pItem->first);
+ pResult.value = pInfo.getStringIdxInPool(pItem->second);
+
+ if (pResult.key == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS pragma list contains invalid string '%s' for key.", pItem->first);
+ return false;
+ }
+
+ if (pResult.value == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS pragma list contains invalid string '%s' for value.",
+ pItem->second);
+ return false;
+ }
+
+ return true;
+}
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::ObjectSlotItem, RSInfo::ObjectSlotListTy>(
+ rsinfo::ObjectSlotItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::ObjectSlotListTy::const_iterator &pItem) {
+ pResult.slot = *pItem;
+ return true;
+}
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::ExportVarNameItem, RSInfo::ExportVarNameListTy>(
+ rsinfo::ExportVarNameItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::ExportVarNameListTy::const_iterator &pItem) {
+ pResult.name = pInfo.getStringIdxInPool(*pItem);
+
+ if (pResult.name == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS export vars contains invalid string '%s' for name.", *pItem);
+ return false;
+ }
+
+ return true;
+}
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::ExportFuncNameItem,
+ RSInfo::ExportFuncNameListTy>(
+ rsinfo::ExportFuncNameItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::ExportFuncNameListTy::const_iterator &pItem) {
+ pResult.name = pInfo.getStringIdxInPool(*pItem);
+
+ if (pResult.name == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS export funcs contains invalid string '%s' for name.", *pItem);
+ return false;
+ }
+
+ return true;
+}
+
+template<> inline bool
+helper_adapt_list_item<rsinfo::ExportForeachFuncItem,
+ RSInfo::ExportForeachFuncListTy>(
+ rsinfo::ExportForeachFuncItem &pResult,
+ const RSInfo &pInfo,
+ const RSInfo::ExportForeachFuncListTy::const_iterator &pItem) {
+ pResult.name = pInfo.getStringIdxInPool(pItem->first);
+ pResult.signature = pItem->second;
+
+ if (pResult.name == rsinfo::gInvalidStringIndex) {
+ ALOGE("RS export foreach contains invalid string '%s' for name.",
+ pItem->first);
+ return false;
+ }
+
+ return true;
+}
+
+template<typename ItemType, typename ItemContainer>
+inline bool helper_write_list(OutputFile &pOutput,
+ const RSInfo &pInfo,
+ const rsinfo::ListHeader &pHeader,
+ ItemContainer &pList) {
+ ItemType item;
+
+ for (typename ItemContainer::const_iterator item_iter = pList.begin(),
+ item_end = pList.end(); item_iter != item_end; item_iter++) {
+ // Convert each entry in the pList to ItemType.
+ if (!helper_adapt_list_item<ItemType, ItemContainer>(item,
+ pInfo,
+ item_iter)) {
+ return false;
+ }
+ // And write out an item.
+ if (pOutput.write(&item, sizeof(item)) != sizeof(item)) {
+ ALOGE("Cannot write out item of %s for RSInfo file %s! (%s)",
+ rsinfo::GetItemTypeName<ItemType>(), pOutput.getName().c_str(),
+ pOutput.getErrorMessage().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // end anonymous namespace
+
+bool RSInfo::write(OutputFile &pOutput) {
+ off_t initial_offset = pOutput.tell();
+ const char *output_filename = pOutput.getName().c_str();
+
+ if (pOutput.hasError()) {
+ ALOGE("Invalid RS info file %s for output! (%s)",
+ output_filename, pOutput.getErrorMessage().c_str());
+ return false;
+ }
+
+ // Layout.
+ if (!layout(initial_offset)) {
+ return false;
+ }
+
+ // Write header.
+ if (pOutput.write(&mHeader, sizeof(mHeader)) != sizeof(mHeader)) {
+ ALOGE("Cannot write out the header for RSInfo file %s! (%s)",
+ output_filename, pOutput.getErrorMessage().c_str());
+ return false;
+ }
+
+ // Write string pool.
+ if (static_cast<size_t>(pOutput.write(mStringPool, mHeader.strPoolSize))
+ != mHeader.strPoolSize) {
+ ALOGE("Cannot write out the string pool for RSInfo file %s! (%s)",
+ output_filename, pOutput.getErrorMessage().c_str());
+ return false;
+ }
+
+ // Write dependencyTable.
+ if (!helper_write_list<rsinfo::DependencyTableItem, DependencyTableTy>
+ (pOutput, *this, mHeader.dependencyTable, mDependencyTable)) {
+ return false;
+ }
+
+ // Write pragmaList.
+ if (!helper_write_list<rsinfo::PragmaItem, PragmaListTy>
+ (pOutput, *this, mHeader.pragmaList, mPragmas)) {
+ return false;
+ }
+
+ // Write objectSlotList.
+ if (!helper_write_list<rsinfo::ObjectSlotItem, ObjectSlotListTy>
+ (pOutput, *this, mHeader.objectSlotList, mObjectSlots)) {
+ return false;
+ }
+
+ // Write exportVarNameList.
+ if (!helper_write_list<rsinfo::ExportVarNameItem, ExportVarNameListTy>
+ (pOutput, *this, mHeader.exportVarNameList, mExportVarNames)) {
+ return false;
+ }
+
+ // Write exportFuncNameList.
+ if (!helper_write_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy>
+ (pOutput, *this, mHeader.exportFuncNameList, mExportFuncNames)) {
+ return false;
+ }
+
+ // Write exportForeachFuncList.
+ if (!helper_write_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy>
+ (pOutput, *this, mHeader.exportForeachFuncList, mExportForeachFuncs)) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/lib/ExecutionEngine/RSScript.cpp b/lib/ExecutionEngine/RSScript.cpp
index d223eee..2ca97a5 100644
--- a/lib/ExecutionEngine/RSScript.cpp
+++ b/lib/ExecutionEngine/RSScript.cpp
@@ -56,10 +56,9 @@
namespace bcc {
-RSScript::SourceDependency::SourceDependency(MCO_ResourceType pSourceType,
- const std::string &pSourceName,
+RSScript::SourceDependency::SourceDependency(const std::string &pSourceName,
const uint8_t *pSHA1)
- : mSourceType(pSourceType), mSourceName(pSourceName) {
+ : mSourceName(pSourceName) {
::memcpy(mSHA1, pSHA1, sizeof(mSHA1));
return;
}
@@ -106,11 +105,10 @@
return true;
}
-bool RSScript::addSourceDependency(MCO_ResourceType pSourceType,
- const std::string &pSourceName,
+bool RSScript::addSourceDependency(const std::string &pSourceName,
const uint8_t *pSHA1) {
SourceDependency *source_dep =
- new (std::nothrow) SourceDependency(pSourceType, pSourceName, pSHA1);
+ new (std::nothrow) SourceDependency(pSourceName, pSHA1);
if (source_dep == NULL) {
ALOGE("Out of memory when record dependency information of `%s'!",
pSourceName.c_str());
@@ -263,13 +261,12 @@
}
// Dependencies
- reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
- reader.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
+ 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->getSourceType(),
- source_dep->getSourceName(),
+ reader.addDependency(source_dep->getSourceName(),
source_dep->getSHA1Checksum());
}
@@ -383,14 +380,13 @@
#ifdef TARGET_BUILD
// Dependencies
- writer.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
- writer.addDependency(BCC_FILE_RESOURCE, pathLibRS, sha1LibRS);
+ 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->getSourceType(),
- source_dep->getSourceName(),
+ writer.addDependency(source_dep->getSourceName(),
source_dep->getSHA1Checksum());
}
diff --git a/lib/ExecutionEngine/RSScript.h b/lib/ExecutionEngine/RSScript.h
index 6e4cd9f..50a3eb3 100644
--- a/lib/ExecutionEngine/RSScript.h
+++ b/lib/ExecutionEngine/RSScript.h
@@ -38,6 +38,7 @@
}
namespace bcc {
+ class RSInfo;
class ScriptCompiled;
class ScriptCached;
class Source;
@@ -64,18 +65,13 @@
public:
class SourceDependency {
private:
- MCO_ResourceType mSourceType;
std::string mSourceName;
uint8_t mSHA1[20];
public:
- SourceDependency(MCO_ResourceType pSourceType,
- const std::string &pSourceName,
+ SourceDependency(const std::string &pSourceName,
const uint8_t *pSHA1);
- inline MCO_ResourceType getSourceType() const
- { return mSourceType; }
-
inline const std::string &getSourceName() const
{ return mSourceName; }
@@ -113,6 +109,8 @@
llvm::SmallVector<SourceDependency *, 4> mSourceDependencies;
+ const RSInfo *mInfo;
+
// External Function List
std::vector<char const *> mUserDefinedExternalSymbols;
@@ -134,13 +132,19 @@
// 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(MCO_ResourceType pSourceType,
- const std::string &pSourceName,
+ 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 markExternalSymbol(char const *name) {
mUserDefinedExternalSymbols.push_back(name);
}
diff --git a/lib/ExecutionEngine/bcc.cpp b/lib/ExecutionEngine/bcc.cpp
index 7425d0a..6baa3e0 100644
--- a/lib/ExecutionEngine/bcc.cpp
+++ b/lib/ExecutionEngine/bcc.cpp
@@ -114,7 +114,7 @@
if (need_dependency_check) {
uint8_t sha1[20];
calcSHA1(sha1, pBitcode, pBitcodeSize);
- if (!pScript->addSourceDependency(BCC_APK_RESOURCE, pName, sha1)) {
+ if (!pScript->addSourceDependency(pName, sha1)) {
return false;
}
}
@@ -164,7 +164,7 @@
if (need_dependency_check) {
uint8_t sha1[20];
calcFileSHA1(sha1, pPath);
- if (!pScript->addSourceDependency(BCC_APK_RESOURCE, pPath, sha1)) {
+ if (!pScript->addSourceDependency(pPath, sha1)) {
return false;
}
}