Add BCC support for rs_object_slots metadata.

This is added to support proper cleanup of RS resources. We were leaking some
global resources because there was no way to tell which slots to clear.

Change-Id: I3e01ff4f7105444b7610d514f10dd56cb1b359b8
b: 3381615
diff --git a/lib/bcc/CacheReader.cpp b/lib/bcc/CacheReader.cpp
index 387e094..a8e252b 100644
--- a/lib/bcc/CacheReader.cpp
+++ b/lib/bcc/CacheReader.cpp
@@ -80,6 +80,7 @@
              && readExportFuncList()
              && readPragmaList()
              && readFuncTable()
+             && readObjectSlotList()
              && readContext()
              && checkContext()
              //&& readRelocationTable()
@@ -384,6 +385,13 @@
 }
 
 
+bool CacheReader::readObjectSlotList() {
+  CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
+                            mpResult->mpObjectSlotList, object_slot_list);
+  return true;
+}
+
+
 bool CacheReader::readFuncTable() {
   CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
 
diff --git a/lib/bcc/CacheReader.h b/lib/bcc/CacheReader.h
index 3f052d0..e66503e 100644
--- a/lib/bcc/CacheReader.h
+++ b/lib/bcc/CacheReader.h
@@ -74,6 +74,7 @@
     bool readExportFuncList();
     bool readPragmaList();
     bool readFuncTable();
+    bool readObjectSlotList();
     bool readContext();
     bool readRelocationTable();
 
diff --git a/lib/bcc/CacheWriter.cpp b/lib/bcc/CacheWriter.cpp
index 6d3a104..27ffd6d 100644
--- a/lib/bcc/CacheWriter.cpp
+++ b/lib/bcc/CacheWriter.cpp
@@ -47,6 +47,7 @@
   CHECK_AND_FREE(mpExportFuncListSection);
   CHECK_AND_FREE(mpPragmaListSection);
   CHECK_AND_FREE(mpFuncTableSection);
+  CHECK_AND_FREE(mpObjectSlotSection);
 
 #undef CHECK_AND_FREE
 }
@@ -68,6 +69,7 @@
              && prepareStringPool()
              && prepareExportVarList()
              && prepareExportFuncList()
+             && prepareObjectSlotList()
              && calcSectionOffset()
              && calcContextChecksum()
              && writeAll()
@@ -307,6 +309,29 @@
 }
 
 
+bool CacheWriter::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 CacheWriter::calcSectionOffset() {
   size_t offset = sizeof(OBCC_Header);
 
@@ -330,6 +355,7 @@
   OFFSET_INCREASE(export_func_list);
   OFFSET_INCREASE(pragma_list);
   OFFSET_INCREASE(func_table);
+  OFFSET_INCREASE(object_slot_list);
 
 #undef OFFSET_INCREASE
 
@@ -388,6 +414,7 @@
   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);
 
   WRITE_SECTION(context, mpHeaderSection->context_offset, BCC_CONTEXT_SIZE,
                 mpOwner->getContext());
diff --git a/lib/bcc/CacheWriter.h b/lib/bcc/CacheWriter.h
index b6d05f6..3e3f0af 100644
--- a/lib/bcc/CacheWriter.h
+++ b/lib/bcc/CacheWriter.h
@@ -48,13 +48,14 @@
     OBCC_ExportFuncList *mpExportFuncListSection;
     OBCC_PragmaList *mpPragmaListSection;
     OBCC_FuncTable *mpFuncTableSection;
+    OBCC_ObjectSlotList *mpObjectSlotSection;
 
   public:
     CacheWriter()
       : mpHeaderSection(NULL), mpStringPoolSection(NULL),
         mpDependencyTableSection(NULL), mpExportVarListSection(NULL),
         mpExportFuncListSection(NULL), mpPragmaListSection(NULL),
-        mpFuncTableSection(NULL) {
+        mpFuncTableSection(NULL), mpObjectSlotSection(NULL) {
     }
 
     ~CacheWriter();
@@ -78,6 +79,7 @@
     bool prepareExportFuncList();
     bool preparePragmaList();
     bool prepareFuncTable();
+    bool prepareObjectSlotList();
 
     bool writeAll();
 
diff --git a/lib/bcc/Compiler.cpp b/lib/bcc/Compiler.cpp
index 05fe017..c8d9eb4 100644
--- a/lib/bcc/Compiler.cpp
+++ b/lib/bcc/Compiler.cpp
@@ -84,18 +84,21 @@
 
 std::vector<std::string> Compiler::Features;
 
-// The named of metadata node that pragma resides (should be synced with
+// Name of metadata node where pragma info resides (should be synced with
 // slang.cpp)
 const llvm::StringRef Compiler::PragmaMetadataName = "#pragma";
 
-// The named of metadata node that export variable name resides (should be
+// Name of metadata node where exported variable names reside (should be
 // synced with slang_rs_metadata.h)
 const llvm::StringRef Compiler::ExportVarMetadataName = "#rs_export_var";
 
-// The named of metadata node that export function name resides (should be
+// Name of metadata node where exported function names reside (should be
 // synced with slang_rs_metadata.h)
 const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func";
 
+// Name of metadata node where RS object slot info resides (should be
+// synced with slang_rs_metadata.h)
+const llvm::StringRef Compiler::ObjectSlotMetadataName = "#rs_object_slots";
 
 //////////////////////////////////////////////////////////////////////////////
 // Compiler
@@ -319,6 +322,7 @@
   const llvm::NamedMDNode *PragmaMetadata;
   const llvm::NamedMDNode *ExportVarMetadata;
   const llvm::NamedMDNode *ExportFuncMetadata;
+  const llvm::NamedMDNode *ObjectSlotMetadata;
 
   if (mModule == NULL)  // No module was loaded
     return 0;
@@ -378,6 +382,7 @@
   ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
   ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
   PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
+  ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName);
 
 #if 0
   mHasLinked = false;
@@ -613,6 +618,28 @@
     }
   }
 
+  if (ObjectSlotMetadata) {
+    ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots;
+
+    for (int i = 0, e = ObjectSlotMetadata->getNumOperands(); i != e; i++) {
+      llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
+      if (ObjectSlot != NULL &&
+          ObjectSlot->getNumOperands() == 1) {
+        llvm::Value *SlotMDS = ObjectSlot->getOperand(0);
+        if (SlotMDS->getValueID() == llvm::Value::MDStringVal) {
+          llvm::StringRef Slot =
+              static_cast<llvm::MDString*>(SlotMDS)->getString();
+          uint32_t USlot = 0;
+          if (Slot.getAsInteger(10, USlot)) {
+            setError("Non-integer object slot value '" + Slot.str() + "'");
+            goto on_bcc_compile_error;
+          }
+          objectSlotList.push_back(USlot);
+        }
+      }
+    }
+  }
+
 on_bcc_compile_error:
   // LOGE("on_bcc_compiler_error");
   if (CodeGenPasses) {
diff --git a/lib/bcc/Compiler.h b/lib/bcc/Compiler.h
index 5f3961c..b90c9e1 100644
--- a/lib/bcc/Compiler.h
+++ b/lib/bcc/Compiler.h
@@ -71,6 +71,7 @@
     static const llvm::StringRef PragmaMetadataName;
     static const llvm::StringRef ExportVarMetadataName;
     static const llvm::StringRef ExportFuncMetadataName;
+    static const llvm::StringRef ObjectSlotMetadataName;
 
     friend class CodeEmitter;
     friend class CodeMemoryManager;
diff --git a/lib/bcc/Script.cpp b/lib/bcc/Script.cpp
index 74b4793..23e8f41 100644
--- a/lib/bcc/Script.cpp
+++ b/lib/bcc/Script.cpp
@@ -367,6 +367,17 @@
 }
 
 
+size_t Script::getObjectSlotCount() const {
+  switch (mStatus) {
+  case ScriptStatus::Compiled:  return mCompiled->getObjectSlotCount();
+#if USE_CACHE
+  case ScriptStatus::Cached:    return mCached->getObjectSlotCount();
+#endif
+  default:                      return 0;
+  }
+}
+
+
 void Script::getExportVarList(size_t varListSize, void **varList) {
   switch (mStatus) {
 #define DELEGATE(STATUS) \
@@ -434,7 +445,7 @@
   switch (mStatus) {
 #define DELEGATE(STATUS) \
   case ScriptStatus::STATUS: \
-    m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList);
+    m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
     break;
 
 #if USE_CACHE
@@ -449,6 +460,28 @@
   }
 }
 
+
+void Script::getObjectSlotList(size_t objectSlotListSize,
+                               uint32_t *objectSlotList) {
+  switch (mStatus) {
+#define DELEGATE(STATUS) \
+  case ScriptStatus::STATUS: \
+    m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
+    break;
+
+#if USE_CACHE
+  DELEGATE(Cached);
+#endif
+
+  DELEGATE(Compiled);
+#undef DELEGATE
+
+  default:
+    mErrorCode = BCC_INVALID_OPERATION;
+  }
+}
+
+
 char *Script::getContext() {
   switch (mStatus) {
 #if USE_CACHE
diff --git a/lib/bcc/Script.h b/lib/bcc/Script.h
index a5ba058..64e4803 100644
--- a/lib/bcc/Script.h
+++ b/lib/bcc/Script.h
@@ -114,6 +114,7 @@
 
     size_t getFuncCount() const;
 
+    size_t getObjectSlotCount() const;
 
     void getExportVarList(size_t size, void **list);
 
@@ -125,6 +126,8 @@
 
     void getFuncInfoList(size_t size, FuncInfo *list);
 
+    void getObjectSlotList(size_t size, uint32_t *list);
+
 
     int registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext);
 
diff --git a/lib/bcc/ScriptCached.cpp b/lib/bcc/ScriptCached.cpp
index b4cf99d..1003163 100644
--- a/lib/bcc/ScriptCached.cpp
+++ b/lib/bcc/ScriptCached.cpp
@@ -37,6 +37,7 @@
   if (mpStringPoolRaw) { free(mpStringPoolRaw); }
   if (mpExportVars) { free(mpExportVars); }
   if (mpExportFuncs) { free(mpExportFuncs); }
+  if (mpObjectSlotList) { free(mpObjectSlotList); }
 }
 
 void ScriptCached::getExportVarList(size_t varListSize, void **varList) {
@@ -89,6 +90,21 @@
 }
 
 
+void ScriptCached::getObjectSlotList(size_t objectSlotListSize,
+                                     uint32_t *objectSlotList) {
+  if (objectSlotList) {
+    size_t objectSlotCount = getObjectSlotCount();
+
+    if (objectSlotCount > objectSlotListSize) {
+      objectSlotCount = objectSlotListSize;
+    }
+
+    memcpy(objectSlotList, mpObjectSlotList->object_slot_list,
+           sizeof(uint32_t) * objectSlotCount);
+  }
+}
+
+
 void *ScriptCached::lookup(const char *name) {
   FuncTable::const_iterator I = mFunctions.find(name);
   return (I == mFunctions.end()) ? NULL : I->second.first;
diff --git a/lib/bcc/ScriptCached.h b/lib/bcc/ScriptCached.h
index c484546..26db663 100644
--- a/lib/bcc/ScriptCached.h
+++ b/lib/bcc/ScriptCached.h
@@ -54,6 +54,7 @@
     OBCC_ExportVarList *mpExportVars;
     OBCC_ExportFuncList *mpExportFuncs;
     PragmaList mPragmas;
+    OBCC_ObjectSlotList *mpObjectSlotList;
 
     FuncTable mFunctions;
 
@@ -67,7 +68,8 @@
   public:
     ScriptCached(Script *owner)
       : mpOwner(owner), mpExportVars(NULL), mpExportFuncs(NULL),
-        mContext(NULL), mpStringPoolRaw(NULL), mLibRSThreadable(false) {
+        mpObjectSlotList(NULL), mContext(NULL), mpStringPoolRaw(NULL),
+        mLibRSThreadable(false) {
     }
 
     ~ScriptCached();
@@ -91,6 +93,9 @@
       return mFunctions.size();
     }
 
+    size_t getObjectSlotCount() const {
+      return mpObjectSlotList->count;
+    }
 
     void getExportVarList(size_t varListSize, void **varList);
 
@@ -102,6 +107,8 @@
 
     void getFuncInfoList(size_t funcInfoListSize, FuncInfo *funcNameList);
 
+    void getObjectSlotList(size_t objectSlotListSize,
+                           uint32_t *objectSlotList);
 
     char *getContext() {
       return mContext;
diff --git a/lib/bcc/ScriptCompiled.cpp b/lib/bcc/ScriptCompiled.cpp
index 052d2a7..5fd45b6 100644
--- a/lib/bcc/ScriptCompiled.cpp
+++ b/lib/bcc/ScriptCompiled.cpp
@@ -117,5 +117,22 @@
   }
 }
 
+void ScriptCompiled::getObjectSlotList(size_t objectSlotListSize,
+                                       uint32_t *objectSlotList) {
+  if (objectSlotList) {
+    size_t objectSlotCount = getObjectSlotCount();
+
+    if (objectSlotCount > objectSlotListSize) {
+      objectSlotCount = objectSlotListSize;
+    }
+
+    for (ObjectSlotList::const_iterator
+         I = mObjectSlots.begin(), E = mObjectSlots.end();
+         I != E && objectSlotCount > 0; ++I, --objectSlotCount) {
+      *objectSlotList++ = *I;
+    }
+  }
+
+}
 
 } // namespace bcc
diff --git a/lib/bcc/ScriptCompiled.h b/lib/bcc/ScriptCompiled.h
index 01af974..0e5c9fc 100644
--- a/lib/bcc/ScriptCompiled.h
+++ b/lib/bcc/ScriptCompiled.h
@@ -43,6 +43,7 @@
     typedef std::list<void*> ExportVarList;
     typedef std::list<void*> ExportFuncList;
     typedef std::map<std::string, FuncInfo *> FuncInfoMap;
+    typedef std::list<uint32_t> ObjectSlotList;
 
   private:
     Script *mpOwner;
@@ -52,6 +53,7 @@
     ExportVarList mExportVars;
     ExportFuncList mExportFuncs;
     PragmaList mPragmas;
+    ObjectSlotList mObjectSlots;
 
     FuncInfoMap mEmittedFunctions;
 
@@ -111,6 +113,9 @@
       return mEmittedFunctions.size();
     }
 
+    size_t getObjectSlotCount() const {
+      return mObjectSlots.size();
+    }
 
     void getExportVarList(size_t varListSize, void **varList);
 
@@ -123,6 +128,9 @@
     void getFuncInfoList(size_t funcInfoListSize,
                          FuncInfo *funcInfoList);
 
+    void getObjectSlotList(size_t objectSlotListSize,
+                           uint32_t *objectSlotList);
+
     char *getContext() {
       return mContext;
     }
diff --git a/lib/bcc/bcc.cpp b/lib/bcc/bcc.cpp
index 294842b..11e3a95 100644
--- a/lib/bcc/bcc.cpp
+++ b/lib/bcc/bcc.cpp
@@ -242,3 +242,33 @@
     unwrap(script)->getFuncInfoList(funcInfoListSize, funcInfoList);
   }
 }
+
+
+extern "C" size_t bccGetObjectSlotCount(BCCScriptRef script) {
+  BCC_FUNC_LOGGER();
+  return unwrap(script)->getObjectSlotCount();
+}
+
+
+extern "C" void bccGetObjectSlotList(BCCScriptRef script,
+                                     size_t objectSlotListSize,
+                                     uint32_t *objectSlotList) {
+  BCC_FUNC_LOGGER();
+
+  if (objectSlotList) {
+    unwrap(script)->getObjectSlotList(objectSlotListSize, objectSlotList);
+#if USE_DISASSEMBLER_FILE
+    size_t count = unwrap(script)->getObjectSlotCount();
+    LOGD("ObjectSlotCount = %lu\n", (unsigned long)count);
+
+    if (count > objectSlotListSize) {
+      count = objectSlotListSize;
+    }
+
+    for (size_t i = 0; i < count; ++i) {
+      LOGD("ObjectSlotList[%lu] = %d\n", (unsigned long)i, objectSlotList[i]);
+    }
+#endif
+  }
+}
+