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