Introduce ObjectLoader and RSExecutable.

ObjectLoader loads an object file into memory.

ObjectLoaderImpl defines a set of format-independent interfaces
that a object file format loader has to provide.

ELFObjectLoaderImpl is a subclass of ObjectLoaderImpl and can be used
to load an ELF relocatable object built based on librsloader. It
directly uses the C++ APIs provided by librsloader instead of using
wrapped C APIs defined in librsloader.h

RSExecutable holds the build results of a RSScript.

Change-Id: Ib73d3f567fce3dcfea8c9f2c9bc19fbc47ec78bc
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index 430f872..02088cb 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -27,13 +27,16 @@
   BCCContextImpl.cpp \
   BCCRuntimeSymbolResolver.cpp \
   Compiler.cpp \
+  ELFObjectLoaderImpl.cpp \
   FileBase.cpp \
   GDBJIT.cpp \
   GDBJITRegistrar.cpp \
   InputFile.cpp \
   MCCacheWriter.cpp \
   MCCacheReader.cpp \
+  ObjectLoader.cpp \
   OutputFile.cpp \
+  RSExecutable.cpp \
   RSInfo.cpp \
   RSInfoExtractor.cpp \
   RSInfoReader.cpp \
@@ -62,7 +65,10 @@
 LOCAL_CFLAGS += $(libbcc_CFLAGS)
 LOCAL_CFLAGS += -DTARGET_BUILD
 
-LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
+LOCAL_C_INCLUDES := \
+  $(libbcc_C_INCLUDES) \
+  $(RSLOADER_ROOT_PATH) \
+  $(RSLOADER_ROOT_PATH)/include
 LOCAL_SRC_FILES := $(libbcc_executionengine_SRC_FILES)
 LOCAL_SHARED_LIBRARIES := libbcinfo
 
@@ -85,7 +91,10 @@
 
 LOCAL_CFLAGS += $(libbcc_CFLAGS)
 LOCAL_CFLAGS += -D__HOST__
-LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
+LOCAL_C_INCLUDES := \
+  $(libbcc_C_INCLUDES) \
+  $(RSLOADER_ROOT_PATH) \
+  $(RSLOADER_ROOT_PATH)/include
 
 LOCAL_SRC_FILES := $(libbcc_executionengine_SRC_FILES)
 LOCAL_SHARED_LIBRARIES := libbcinfo
diff --git a/lib/ExecutionEngine/ELFObjectLoaderImpl.cpp b/lib/ExecutionEngine/ELFObjectLoaderImpl.cpp
new file mode 100644
index 0000000..01f613e
--- /dev/null
+++ b/lib/ExecutionEngine/ELFObjectLoaderImpl.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#include "ELFObjectLoaderImpl.h"
+
+#include <llvm/Support/ELF.h>
+
+// The following files are included from librsloader.
+#include "ELFObject.h"
+#include "ELFSectionSymTab.h"
+#include "ELFSymbol.h"
+#include "utils/serialize.h"
+
+#include "DebugHelper.h"
+#include "SymbolResolverInterface.h"
+
+using namespace bcc;
+
+bool ELFObjectLoaderImpl::load(const void *pMem, size_t pMemSize) {
+  ArchiveReaderLE reader(reinterpret_cast<const unsigned char *>(pMem),
+                         pMemSize);
+
+  mObject = ELFObject<32>::read(reader);
+  if (mObject == NULL) {
+    ALOGE("Unable to load the ELF object!");
+    return false;
+  }
+
+  // Retrive the pointer to the symbol table.
+  mSymTab = static_cast<ELFSectionSymTab<32> *>(
+                mObject->getSectionByName(".symtab"));
+  if (mSymTab == NULL) {
+    ALOGW("Object doesn't contain any symbol table.");
+  }
+
+  return true;
+}
+
+bool ELFObjectLoaderImpl::relocate(SymbolResolverInterface &pResolver) {
+  mObject->relocate(SymbolResolverInterface::LookupFunction, &pResolver);
+
+  if (mObject->getMissingSymbols()) {
+    ALOGE("Some symbols are found to be undefined during relocation!");
+    return false;
+  }
+
+  return true;
+}
+
+bool ELFObjectLoaderImpl::prepareDebugImage(void *pDebugImg,
+                                            size_t pDebugImgSize) {
+  // Update the value of sh_addr in pDebugImg to its corresponding section in
+  // the mObject.
+  llvm::ELF::Elf32_Ehdr *elf_header =
+      reinterpret_cast<llvm::ELF::Elf32_Ehdr *>(pDebugImg);
+
+  if (elf_header->e_shoff > pDebugImgSize) {
+    ALOGE("Invalid section header table offset found! (e_shoff = %d)",
+          elf_header->e_shoff);
+    return false;
+  }
+
+  if ((elf_header->e_shoff +
+       sizeof(llvm::ELF::Elf32_Shdr) * elf_header->e_shnum) > pDebugImgSize) {
+    ALOGE("Invalid image supplied (debug image doesn't contain all the section"
+          "header or corrupted image)! (e_shoff = %d, e_shnum = %d)",
+          elf_header->e_shoff, elf_header->e_shnum);
+    return false;
+  }
+
+  llvm::ELF::Elf32_Shdr *section_header_table =
+      reinterpret_cast<llvm::ELF::Elf32_Shdr *>(
+          reinterpret_cast<uint8_t*>(pDebugImg) + elf_header->e_shoff);
+
+  for (unsigned i = 0; i < elf_header->e_shnum; i++) {
+    if (section_header_table[i].sh_flags & llvm::ELF::SHF_ALLOC) {
+      ELFSectionBits<32> *section =
+          static_cast<ELFSectionBits<32> *>(mObject->getSectionByIndex(i));
+      if (section != NULL) {
+        section_header_table[i].sh_addr =
+            reinterpret_cast<llvm::ELF::Elf32_Addr>(section->getBuffer());
+      }
+    }
+  }
+
+  return true;
+}
+
+void *ELFObjectLoaderImpl::getSymbolAddress(const char *pName) const {
+  if (mSymTab == NULL) {
+    return NULL;
+  }
+
+  ELFSymbol<32> *symbol = mSymTab->getByName(pName);
+  if (symbol == NULL) {
+    ALOGV("Request symbol '%s' is not found in the object!", pName);
+    return NULL;
+  }
+
+  return symbol->getAddress(mObject->getHeader()->getMachine(),
+                            /* autoAlloc */false);
+}
+
+ELFObjectLoaderImpl::~ELFObjectLoaderImpl() {
+  delete mObject;
+  return;
+}
diff --git a/lib/ExecutionEngine/ELFObjectLoaderImpl.h b/lib/ExecutionEngine/ELFObjectLoaderImpl.h
new file mode 100644
index 0000000..37766fb
--- /dev/null
+++ b/lib/ExecutionEngine/ELFObjectLoaderImpl.h
@@ -0,0 +1,53 @@
+/*
+ * 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_ELF_OBJECT_LOADER_IMPL_H
+#define BCC_EXECUTION_ENGINE_ELF_OBJECT_LOADER_IMPL_H
+
+#include "ObjectLoaderImpl.h"
+
+// ELFObject and ELFSectionSymTab comes from librsloader. They're both
+// defined under global scope without a namespace enclosed.
+template <unsigned Bitwidth>
+class ELFObject;
+
+template <unsigned Bitwidth>
+class ELFSectionSymTab;
+
+namespace bcc {
+
+class ELFObjectLoaderImpl : public ObjectLoaderImpl {
+private:
+  ELFObject<32> *mObject;
+  ELFSectionSymTab<32> *mSymTab;
+
+public:
+  ELFObjectLoaderImpl() : ObjectLoaderImpl(), mObject(NULL), mSymTab(NULL) { }
+
+  virtual bool load(const void *pMem, size_t pMemSize);
+
+  virtual bool relocate(SymbolResolverInterface &pResolver);
+
+  virtual bool prepareDebugImage(void *pDebugImg, size_t pDebugImgSize);
+
+  virtual void *getSymbolAddress(const char *pName) const;
+
+  ~ELFObjectLoaderImpl();
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_ELF_OBJECT_LOADER_IMPL_H
diff --git a/lib/ExecutionEngine/ObjectLoader.cpp b/lib/ExecutionEngine/ObjectLoader.cpp
new file mode 100644
index 0000000..708ded3
--- /dev/null
+++ b/lib/ExecutionEngine/ObjectLoader.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+#include "ObjectLoader.h"
+
+#include <utils/FileMap.h>
+
+#include "DebugHelper.h"
+#include "ELFObjectLoaderImpl.h"
+#include "FileBase.h"
+#include "GDBJITRegistrar.h"
+
+using namespace bcc;
+
+ObjectLoader *ObjectLoader::Load(void *pMemStart, size_t pMemSize,
+                                 const char *pName,
+                                 SymbolResolverInterface &pResolver,
+                                 bool pEnableGDBDebug) {
+  ObjectLoader *result = NULL;
+
+  // Check parameters.
+  if ((pMemStart == NULL) || (pMemSize <= 0)) {
+    ALOGE("Invalid memory '%s' was given to load (memory addr: %p, size: %u)",
+          pName, pMemStart, static_cast<unsigned>(pMemSize));
+    goto bail;
+  }
+
+  // Create result object
+  result = new (std::nothrow) ObjectLoader();
+  if (result == NULL) {
+    ALOGE("Out of memory when create object loader for %s!", pName);
+    goto bail;
+  }
+
+  // Currently, only ELF object loader is supported. Therefore, there's no codes
+  // to detect the object file type and to select the one appropriated. Directly
+  // try out the ELF object loader.
+  result->mImpl = new (std::nothrow) ELFObjectLoaderImpl();
+  if (result->mImpl == NULL) {
+    ALOGE("Out of memory when create ELF object loader for %s", pName);
+    goto bail;
+  }
+
+  // Load the object file.
+  if (!result->mImpl->load(pMemStart, pMemSize)) {
+    ALOGE("Failed to load %s!", pName);
+    goto bail;
+  }
+
+  // Perform relocation.
+  if (!result->mImpl->relocate(pResolver)) {
+    ALOGE("Error occurred when performs relocation on %s!", pName);
+    goto bail;
+  }
+
+  // GDB debugging is enabled. Note that error occurrs during the setup of
+  // debugging won't failed the object load. Only a warning is issued to notify
+  // that the debugging is disabled due to the failure.
+  if (pEnableGDBDebug) {
+    // GDB's JIT debugging requires the source object file corresponded to the
+    // process image desired to debug with. And some fields in the object file
+    // must be updated to record the runtime information after it's loaded into
+    // memory. For example, GDB's JIT debugging requires an ELF file with the
+    // value of sh_addr in the section header to be the memory address that the
+    // section lives in the process image. Therefore, a writable memory with its
+    // contents initialized to the contents of pFile is created.
+    result->mDebugImage = new (std::nothrow) uint8_t [ pMemSize ];
+    if (result->mDebugImage != NULL) {
+      ::memcpy(result->mDebugImage, pMemStart, pMemSize);
+      if (!result->mImpl->prepareDebugImage(result->mDebugImage, pMemSize)) {
+        ALOGW("GDB debug for %s is enabled by the user but won't work due to "
+              "failure debug image preparation!", pName);
+      } else {
+        registerObjectWithGDB(
+            reinterpret_cast<const ObjectBuffer *>(result->mDebugImage),
+            pMemSize);
+      }
+    }
+  }
+
+  return result;
+
+bail:
+  delete result;
+  return NULL;
+}
+
+ObjectLoader *ObjectLoader::Load(FileBase &pFile,
+                                 SymbolResolverInterface &pResolver,
+                                 bool pEnableGDBDebug) {
+  size_t file_size;
+  android::FileMap *file_map = NULL;
+  const char *input_filename = pFile.getName().c_str();
+  ObjectLoader *result = NULL;
+
+  // Check the inputs.
+  if (pFile.hasError()) {
+    ALOGE("Input file %s to the object loader is in the invalid state! (%s)",
+          input_filename, pFile.getErrorMessage().c_str());
+    return NULL;
+  }
+
+  // Get the file size.
+  file_size = pFile.getSize();
+  if (pFile.hasError()) {
+    ALOGE("Failed to get size of file %s! (%s)", input_filename,
+          pFile.getErrorMessage().c_str());
+    return NULL;
+  }
+
+  // Abort on empty file.
+  if (file_size <= 0) {
+    ALOGE("Empty file %s to the object loader.", input_filename);
+    return NULL;
+  }
+
+  // Create memory map for the input file.
+  file_map = pFile.createMap(0, file_size, /* pIsReadOnly */true);
+  if ((file_map == NULL) || pFile.hasError())  {
+    ALOGE("Failed to map the file %s to the memory! (%s)", input_filename,
+          pFile.getErrorMessage().c_str());
+    return NULL;
+  }
+
+  // Delegate the load request.
+  result = Load(file_map->getDataPtr(), file_size, input_filename, pResolver,
+                pEnableGDBDebug);
+
+  // No whether the load is successful or not, file_map is no longer needed. On
+  // success, there's a copy of the object corresponded to the pFile in the
+  // memory. Therefore, file_map can be safely released.
+  file_map->release();
+
+  return result;
+}
+
+void *ObjectLoader::getSymbolAddress(const char *pName) const {
+  return mImpl->getSymbolAddress(pName);
+}
+
+ObjectLoader::~ObjectLoader() {
+  delete mImpl;
+  delete [] reinterpret_cast<uint8_t *>(mDebugImage);
+}
diff --git a/lib/ExecutionEngine/ObjectLoader.h b/lib/ExecutionEngine/ObjectLoader.h
new file mode 100644
index 0000000..6c2bc8c
--- /dev/null
+++ b/lib/ExecutionEngine/ObjectLoader.h
@@ -0,0 +1,54 @@
+/*
+ * 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_OBJECT_LOADER_H
+#define BCC_EXECUTION_ENGINE_OBJECT_LOADER_H
+
+#include <cstddef>
+
+namespace bcc {
+
+class FileBase;
+class ObjectLoaderImpl;
+class SymbolResolverInterface;
+
+class ObjectLoader {
+private:
+  ObjectLoaderImpl *mImpl;
+
+  void *mDebugImage;
+
+  ObjectLoader() : mImpl(NULL), mDebugImage(0) { }
+
+public:
+  // Load from a in-memory object. pName is a descriptive name of this memory.
+  static ObjectLoader *Load(void *pMemStart, size_t pMemSize, const char *pName,
+                            SymbolResolverInterface &pResolver,
+                            bool pEnableGDBDebug);
+
+  // Load from a file.
+  static ObjectLoader *Load(FileBase &pFile,
+                            SymbolResolverInterface &pResolver,
+                            bool pEnableGDBDebug);
+
+  void *getSymbolAddress(const char *pName) const;
+
+  ~ObjectLoader();
+};
+
+} // namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_OBJECT_LOADER_H
diff --git a/lib/ExecutionEngine/ObjectLoaderImpl.h b/lib/ExecutionEngine/ObjectLoaderImpl.h
new file mode 100644
index 0000000..81756f8
--- /dev/null
+++ b/lib/ExecutionEngine/ObjectLoaderImpl.h
@@ -0,0 +1,43 @@
+/*
+ * 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_OBJECT_LOADER_IMPL_H
+#define BCC_EXECUTION_ENGINE_OBJECT_LOADER_IMPL_H
+
+#include <cstring>
+
+namespace bcc {
+
+class SymbolResolverInterface;
+
+class ObjectLoaderImpl {
+public:
+  ObjectLoaderImpl() { }
+
+  virtual bool load(const void *pMem, size_t pMemSize) = 0;
+
+  virtual bool relocate(SymbolResolverInterface &pResolver) = 0;
+
+  virtual bool prepareDebugImage(void *pDebugImg, size_t pDebugImgSize) = 0;
+
+  virtual void *getSymbolAddress(const char *pName) const = 0;
+
+  virtual ~ObjectLoaderImpl() { }
+};
+
+} // namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_OBJECT_LOADER_IMPL_H
diff --git a/lib/ExecutionEngine/RSExecutable.cpp b/lib/ExecutionEngine/RSExecutable.cpp
new file mode 100644
index 0000000..46ec726
--- /dev/null
+++ b/lib/ExecutionEngine/RSExecutable.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#include "RSExecutable.h"
+
+#include "DebugHelper.h"
+#include "FileBase.h"
+#include "OutputFile.h"
+#include "SymbolResolverProxy.h"
+
+#include <utils/String8.h>
+
+using namespace bcc;
+
+const char *RSExecutable::SpecialFunctionNames[] = {
+  "root",
+  "init",
+  ".rs.dtor",
+  // Must be NULL-terminated.
+  NULL
+};
+
+RSExecutable *RSExecutable::Create(RSInfo &pInfo,
+                                   FileBase &pObjFile,
+                                   SymbolResolverProxy &pResolver) {
+  // Load the object file. Enable the GDB's JIT debugging if the script contains
+  // debug information.
+  ObjectLoader *loader = ObjectLoader::Load(pObjFile,
+                                            pResolver,
+                                            pInfo.hasDebugInformation());
+  if (loader == NULL) {
+    return NULL;
+  }
+
+  // Now, all things required to build a RSExecutable object are ready.
+  RSExecutable *result = new (std::nothrow) RSExecutable(pInfo,
+                                                         pObjFile,
+                                                         *loader);
+  if (result == NULL) {
+    ALOGE("Out of memory when create object to hold RS result file for %s!",
+          pObjFile.getName().c_str());
+    return NULL;
+  }
+
+  unsigned idx;
+  // Resolve addresses of RS export vars.
+  idx = 0;
+  const RSInfo::ExportVarNameListTy &export_var_names =
+      pInfo.getExportVarNames();
+  for (RSInfo::ExportVarNameListTy::const_iterator
+           var_iter = export_var_names.begin(),
+           var_end = export_var_names.end(); var_iter != var_end;
+       var_iter++, idx++) {
+    const char *name = *var_iter;
+    void *addr = result->getSymbolAddress(name);
+    if (addr == NULL) {
+      ALOGW("RS export var at entry #%u named %s cannot be found in the result "
+            "object!", idx, name);
+    }
+    result->mExportVarAddrs.push_back(addr);
+  }
+
+  // Resolve addresses of RS export functions.
+  idx = 0;
+  const RSInfo::ExportFuncNameListTy &export_func_names =
+      pInfo.getExportFuncNames();
+  for (RSInfo::ExportFuncNameListTy::const_iterator
+           func_iter = export_func_names.begin(),
+           func_end = export_func_names.end(); func_iter != func_end;
+       func_iter++, idx++) {
+    const char *name = *func_iter;
+    void *addr = result->getSymbolAddress(name);
+    if (addr == NULL) {
+      ALOGW("RS export func at entry #%u named %s cannot be found in the result"
+            " object!", idx, name);
+    }
+    result->mExportFuncAddrs.push_back(addr);
+  }
+
+  // Resolve addresses of expanded RS foreach function.
+  idx = 0;
+  const RSInfo::ExportForeachFuncListTy &export_foreach_funcs =
+      pInfo.getExportForeachFuncs();
+  for (RSInfo::ExportForeachFuncListTy::const_iterator
+           foreach_iter = export_foreach_funcs.begin(),
+           foreach_end = export_foreach_funcs.end();
+       foreach_iter != foreach_end; foreach_iter++, idx++) {
+    const char *func_name = foreach_iter->first;
+    android::String8 expanded_func_name(func_name);
+    expanded_func_name.append(".expand");
+    void *addr = result->getSymbolAddress(expanded_func_name.string());
+    if (addr == NULL) {
+      ALOGW("Expanded RS foreach at entry #%u named %s cannot be found in the "
+            "result object!", idx, expanded_func_name.string());
+    }
+    result->mExportForeachFuncAddrs.push_back(addr);
+  }
+
+  // Copy pragma key/value pairs from RSInfo::getPragmas() into mPragmaKeys and
+  // mPragmaValues, respectively.
+  const RSInfo::PragmaListTy &pragmas = pInfo.getPragmas();
+  for (RSInfo::PragmaListTy::const_iterator pragma_iter = pragmas.begin(),
+          pragma_end = pragmas.end(); pragma_iter != pragma_end;
+       pragma_iter++){
+    result->mPragmaKeys.push_back(pragma_iter->first);
+    result->mPragmaValues.push_back(pragma_iter->second);
+  }
+
+  return result;
+}
+
+bool RSExecutable::syncInfo(bool pForce) {
+  if (!pForce && !mIsInfoDirty) {
+    return true;
+  }
+
+  android::String8 info_path = RSInfo::GetPath(*mObjFile);
+  OutputFile info_file(info_path.string());
+
+  if (info_file.hasError()) {
+    ALOGE("Failed to open the info file %s for write! (%s)", info_path.string(),
+          info_file.getErrorMessage().c_str());
+    return false;
+  }
+
+  // Operation to the RS info file need to acquire the lock on the output file
+  // first.
+  if (!mObjFile->lock(FileBase::kWriteLock)) {
+    ALOGE("Write to RS info file %s required the acquisition of the write lock "
+          "on %s but got failure! (%s)", info_path.string(),
+          mObjFile->getName().c_str(), info_file.getErrorMessage().c_str());
+    return false;
+  }
+
+  // Perform the write.
+  if (!mInfo->write(info_file)) {
+    ALOGE("Failed to sync the RS info file %s!", info_path.string());
+    mObjFile->unlock();
+    return false;
+  }
+
+  mObjFile->unlock();
+  mIsInfoDirty = false;
+  return true;
+}
+
+RSExecutable::~RSExecutable() {
+  syncInfo();
+  delete mInfo;
+  delete mObjFile;
+  delete mLoader;
+}
diff --git a/lib/ExecutionEngine/RSExecutable.h b/lib/ExecutionEngine/RSExecutable.h
new file mode 100644
index 0000000..12e0f0a
--- /dev/null
+++ b/lib/ExecutionEngine/RSExecutable.h
@@ -0,0 +1,109 @@
+/*
+ * 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_EXECUTABLE_H
+#define BCC_EXECUTION_ENGINE_RS_EXECUTABLE_H
+
+#include <cstddef>
+
+#include "DebugHelper.h"
+#include "ObjectLoader.h"
+#include "RSInfo.h"
+
+#include <utils/Vector.h>
+
+namespace bcc {
+
+class FileBase;
+class SymbolResolverProxy;
+
+/*
+ * RSExecutable holds the build results of a RSScript.
+ */
+class RSExecutable {
+private:
+  RSInfo *mInfo;
+  bool mIsInfoDirty;
+
+  FileBase *mObjFile;
+
+  ObjectLoader *mLoader;
+
+  // Memory address of rs export stuffs
+  android::Vector<void *> mExportVarAddrs;
+  android::Vector<void *> mExportFuncAddrs;
+  android::Vector<void *> mExportForeachFuncAddrs;
+
+  // FIXME: These are designed for RenderScript HAL and is initialized in
+  //        RSExecutable::Create(). Both of them come from RSInfo::getPragmas().
+  //        If possible, read the pragma key/value pairs directly from RSInfo.
+  android::Vector<const char *> mPragmaKeys;
+  android::Vector<const char *> mPragmaValues;
+
+  RSExecutable(RSInfo &pInfo, FileBase &pObjFile, ObjectLoader &pLoader)
+    : mInfo(&pInfo), mIsInfoDirty(false), mObjFile(&pObjFile), mLoader(&pLoader)
+  { }
+
+public:
+  // This is a NULL-terminated string array which specifies "Special" functions
+  // in RenderScript (e.g., root().)
+  static const char *SpecialFunctionNames[];
+
+  // Return NULL on error. If the return object is non-NULL, it claims the
+  // ownership of pInfo and pObjFile.
+  static RSExecutable *Create(RSInfo &pInfo,
+                              FileBase &pObjFile,
+                              SymbolResolverProxy &pResolver);
+
+  inline const RSInfo &getInfo() const
+  { return *mInfo; }
+
+  // Interfaces to RSInfo
+  inline bool isThreadable() const
+  { return mInfo->isThreadable(); }
+
+  inline void setThreadable(bool pThreadable = true) {
+    if (mInfo->isThreadable() != pThreadable) {
+      mInfo->setThreadable(pThreadable);
+      mIsInfoDirty = true;
+    }
+    return;
+  }
+
+  // Interfaces to ObjectLoader
+  inline void *getSymbolAddress(const char *pName) const
+  { return mLoader->getSymbolAddress(pName); }
+
+  bool syncInfo(bool pForce = false);
+
+  inline const android::Vector<void *> &getExportVarAddrs() const
+  { return mExportVarAddrs; }
+  inline const android::Vector<void *> &getExportFuncAddrs() const
+  { return mExportFuncAddrs; }
+  inline const android::Vector<void *> &getExportForeachFuncAddrs() const
+  { return mExportForeachFuncAddrs; }
+
+  inline const android::Vector<const char *> &getPragmaKeys() const
+  { return mPragmaKeys; }
+  inline const android::Vector<const char *> &getPragmaValues() const
+  { return mPragmaValues; }
+
+  ~RSExecutable();
+};
+
+} // end namespace bcc
+
+#endif // BCC_EXECUTION_ENGINE_RS_EXECUTABLE_H