Clean up IndirectRefTable a bit.

The main purpose here was to have slightly less unclear warnings for
JNI local reference abuse.

Change-Id: I2c6378dd0a94d8afb96a8e409f7460205e3cd315
diff --git a/vm/IndirectRefTable.cpp b/vm/IndirectRefTable.cpp
index 225d8c2..270727c 100644
--- a/vm/IndirectRefTable.cpp
+++ b/vm/IndirectRefTable.cpp
@@ -19,32 +19,31 @@
  */
 #include "Dalvik.h"
 
-/*
- * Initialize an IndirectRefTable structure.
- */
-bool dvmInitIndirectRefTable(IndirectRefTable* pRef, int initialCount,
-    int maxCount, IndirectRefKind kind)
+bool IndirectRefTable::init(size_t initialCount,
+        size_t maxCount, IndirectRefKind desiredKind)
 {
     assert(initialCount > 0);
     assert(initialCount <= maxCount);
     assert(kind != kIndirectKindInvalid);
 
-    pRef->table = (Object**) malloc(initialCount * sizeof(Object*));
-    if (pRef->table == NULL)
+    table = (Object**) malloc(initialCount * sizeof(Object*));
+    if (table == NULL) {
         return false;
+    }
 #ifndef NDEBUG
-    memset(pRef->table, 0xd1, initialCount * sizeof(Object*));
+    memset(table, 0xd1, initialCount * sizeof(Object*));
 #endif
 
-    pRef->slotData =
+    slotData =
         (IndirectRefSlot*) calloc(maxCount, sizeof(IndirectRefSlot));
-    if (pRef->slotData == NULL)
+    if (slotData == NULL) {
         return false;
+    }
 
-    pRef->segmentState.all = IRT_FIRST_SEGMENT;
-    pRef->allocEntries = initialCount;
-    pRef->maxEntries = maxCount;
-    pRef->kind = kind;
+    segmentState.all = IRT_FIRST_SEGMENT;
+    allocEntries = initialCount;
+    maxEntries = maxCount;
+    kind = desiredKind;
 
     return true;
 }
@@ -52,133 +51,69 @@
 /*
  * Clears out the contents of a IndirectRefTable, freeing allocated storage.
  */
-void dvmClearIndirectRefTable(IndirectRefTable* pRef)
+void IndirectRefTable::destroy()
 {
-    free(pRef->table);
-    free(pRef->slotData);
-    pRef->table = NULL;
-    pRef->allocEntries = pRef->maxEntries = -1;
-}
-
-/*
- * Remove one or more segments from the top.  The table entry identified
- * by "cookie" becomes the new top-most entry.
- *
- * Returns false if "cookie" is invalid or the table has only one segment.
- */
-bool dvmPopIndirectRefTableSegmentCheck(IndirectRefTable* pRef, u4 cookie)
-{
-    IRTSegmentState sst;
-
-    /*
-     * The new value for "top" must be <= the current value.  Otherwise
-     * this would represent an expansion of the table.
-     */
-    sst.all = cookie;
-    if (sst.parts.topIndex > pRef->segmentState.parts.topIndex) {
-        LOGE("Attempt to expand table with segment pop (%d to %d)",
-            pRef->segmentState.parts.topIndex, sst.parts.topIndex);
-        return false;
-    }
-    if (sst.parts.numHoles >= sst.parts.topIndex) {
-        LOGE("Absurd numHoles in cookie (%d bi=%d)",
-            sst.parts.numHoles, sst.parts.topIndex);
-        return false;
-    }
-
-    LOGV("IRT %p[%d]: pop, top=%d holes=%d",
-        pRef, pRef->kind, sst.parts.topIndex, sst.parts.numHoles);
-
-    return true;
+    free(table);
+    free(slotData);
+    table = NULL;
+    allocEntries = maxEntries = -1;
 }
 
 /*
  * Make sure that the entry at "idx" is correctly paired with "iref".
  */
-static bool checkEntry(IndirectRefTable* pRef, IndirectRef iref, int idx)
+bool IndirectRefTable::checkEntry(IndirectRef iref, int idx) const
 {
-    Object* obj = pRef->table[idx];
-    IndirectRef checkRef = dvmObjectToIndirectRef(pRef, obj, idx, pRef->kind);
+    Object* obj = table[idx];
+    IndirectRef checkRef = toIndirectRef(obj, idx);
     if (checkRef != iref) {
-        LOGW("IRT %p[%d]: iref mismatch (req=%p vs cur=%p)",
-            pRef, pRef->kind, iref, checkRef);
+        LOGE("Attempt to use stale %s reference (req=%p vs cur=%p; table=%p)",
+                indirectRefKindToString(kind), iref, checkRef, this);
         return false;
     }
     return true;
 }
 
-/*
- * Update extended debug info when an entry is added.
- *
- * We advance the serial number, invalidating any outstanding references to
- * this slot.
- */
-static inline void updateSlotAdd(IndirectRefTable* pRef, Object* obj, int slot)
-{
-    if (pRef->slotData != NULL) {
-        IndirectRefSlot* pSlot = &pRef->slotData[slot];
-        pSlot->serial++;
-        //LOGI("+++ add [%d] slot %d (%p->%p), serial=%d",
-        //    pRef->kind, slot, obj, iref, pSlot->serial);
-        pSlot->previous[pSlot->serial % kIRTPrevCount] = obj;
-    }
-}
-
-/*
- * Update extended debug info when an entry is removed.
- */
-static inline void updateSlotRemove(IndirectRefTable* pRef, int slot)
-{
-    if (pRef->slotData != NULL) {
-        //IndirectRefSlot* pSlot = &pRef->slotData[slot];
-        //LOGI("+++ remove [%d] slot %d, serial now %d",
-        //    pRef->kind, slot, pSlot->serial);
-    }
-}
-
-/*
- * Add "obj" to "pRef".
- */
-IndirectRef dvmAddToIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
-    Object* obj)
+IndirectRef IndirectRefTable::add(u4 cookie, Object* obj)
 {
     IRTSegmentState prevState;
     prevState.all = cookie;
-    int topIndex = pRef->segmentState.parts.topIndex;
+    size_t topIndex = segmentState.parts.topIndex;
 
     assert(obj != NULL);
     assert(dvmIsValidObject(obj));
-    assert(pRef->table != NULL);
-    assert(pRef->allocEntries <= pRef->maxEntries);
-    assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
+    assert(table != NULL);
+    assert(allocEntries <= maxEntries);
+    assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
 
-    if (topIndex == pRef->allocEntries) {
+    if (topIndex == allocEntries) {
         /* reached end of allocated space; did we hit buffer max? */
-        if (topIndex == pRef->maxEntries) {
-            LOGW("IndirectRefTable overflow (max=%d)", pRef->maxEntries);
+        if (topIndex == maxEntries) {
+            LOGW("%s reference table overflow (max=%d)",
+                    indirectRefKindToString(kind), maxEntries);
             return NULL;
         }
 
-        Object** newTable;
-        int newSize;
+        size_t newSize = allocEntries * 2;
+        if (newSize > maxEntries) {
+            newSize = maxEntries;
+        }
+        assert(newSize > allocEntries);
 
-        newSize = pRef->allocEntries * 2;
-        if (newSize > pRef->maxEntries)
-            newSize = pRef->maxEntries;
-        assert(newSize > pRef->allocEntries);
-
-        newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
+        Object** newTable = (Object**) realloc(table, newSize * sizeof(Object*));
         if (newTable == NULL) {
-            LOGE("Unable to expand iref table (from %d to %d, max=%d)",
-                pRef->allocEntries, newSize, pRef->maxEntries);
+            LOGE("Unable to expand %s reference table from %d to %d (max=%d)",
+                    indirectRefKindToString(kind), allocEntries,
+                    newSize, maxEntries);
             return false;
         }
-        LOGV("Growing ireftab %p from %d to %d (max=%d)",
-            pRef, pRef->allocEntries, newSize, pRef->maxEntries);
+        LOGV("Growing %s reference table %p from %d to %d (max=%d)",
+                indirectRefKindToString(kind), this,
+                allocEntries, newSize, maxEntries);
 
         /* update entries; adjust "nextEntry" in case memory moved */
-        pRef->table = newTable;
-        pRef->allocEntries = newSize;
+        table = newTable;
+        allocEntries = newSize;
     }
 
     IndirectRef result;
@@ -188,26 +123,25 @@
      * the right spot.  If there's a hole, find it and fill it; otherwise,
      * add to the end of the list.
      */
-    int numHoles = pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
+    int numHoles = segmentState.parts.numHoles - prevState.parts.numHoles;
     if (numHoles > 0) {
         assert(topIndex > 1);
         /* find the first hole; likely to be near the end of the list */
-        Object** pScan = &pRef->table[topIndex - 1];
+        Object** pScan = &table[topIndex - 1];
         assert(*pScan != NULL);
         while (*--pScan != NULL) {
-            assert(pScan >= pRef->table + prevState.parts.topIndex);
+            assert(pScan >= table + prevState.parts.topIndex);
         }
-        updateSlotAdd(pRef, obj, pScan - pRef->table);
-        result = dvmObjectToIndirectRef(pRef, obj, pScan - pRef->table,
-            pRef->kind);
+        updateSlotAdd(obj, pScan - table);
+        result = toIndirectRef(obj, pScan - table);
         *pScan = obj;
-        pRef->segmentState.parts.numHoles--;
+        segmentState.parts.numHoles--;
     } else {
         /* add to the end */
-        updateSlotAdd(pRef, obj, topIndex);
-        result = dvmObjectToIndirectRef(pRef, obj, topIndex, pRef->kind);
-        pRef->table[topIndex++] = obj;
-        pRef->segmentState.parts.topIndex = topIndex;
+        updateSlotAdd(obj, topIndex);
+        result = toIndirectRef(obj, topIndex);
+        table[topIndex++] = obj;
+        segmentState.parts.topIndex = topIndex;
     }
 
     assert(result != NULL);
@@ -219,34 +153,37 @@
  *
  * Returns "false" if something looks bad.
  */
-bool dvmGetFromIndirectRefTableCheck(IndirectRefTable* pRef, IndirectRef iref)
+bool IndirectRefTable::getChecked(IndirectRef iref) const
 {
-    if (dvmGetIndirectRefType(iref) == kIndirectKindInvalid) {
-        LOGW("Invalid indirect reference 0x%08x", (u4) iref);
-        return false;
-    }
-
-    int topIndex = pRef->segmentState.parts.topIndex;
-    int idx = dvmIndirectRefToIndex(iref);
-
     if (iref == NULL) {
-        LOGD("Attempt to look up NULL iref");
+        LOGW("Attempt to look up NULL %s reference",
+                indirectRefKindToString(kind));
         return false;
     }
+    if (indirectRefKind(iref) == kIndirectKindInvalid) {
+        LOGW("Invalid %s reference %p",
+                indirectRefKindToString(kind), iref);
+        return false;
+    }
+
+    int topIndex = segmentState.parts.topIndex;
+    int idx = extractIndex(iref);
     if (idx >= topIndex) {
         /* bad -- stale reference? */
-        LOGD("Attempt to access invalid index %d (top=%d)",
-            idx, topIndex);
+        LOGW("Attempt to access stale %s reference at index %d (top=%d)",
+            indirectRefKindToString(kind), idx, topIndex);
         return false;
     }
 
-    Object* obj = pRef->table[idx];
+    Object* obj = table[idx];
     if (obj == NULL) {
-        LOGD("Attempt to read from hole, iref=%p", iref);
+        LOGW("Attempt to access deleted %s reference (%p)",
+                indirectRefKindToString(kind), iref);
         return false;
     }
-    if (!checkEntry(pRef, iref, idx))
+    if (!checkEntry(iref, idx)) {
         return false;
+    }
 
     return true;
 }
@@ -264,19 +201,18 @@
  *
  * Returns "false" if nothing was removed.
  */
-bool dvmRemoveFromIndirectRefTable(IndirectRefTable* pRef, u4 cookie,
-    IndirectRef iref)
+bool IndirectRefTable::remove(u4 cookie, IndirectRef iref)
 {
     IRTSegmentState prevState;
     prevState.all = cookie;
-    int topIndex = pRef->segmentState.parts.topIndex;
+    int topIndex = segmentState.parts.topIndex;
     int bottomIndex = prevState.parts.topIndex;
 
-    assert(pRef->table != NULL);
-    assert(pRef->allocEntries <= pRef->maxEntries);
-    assert(pRef->segmentState.parts.numHoles >= prevState.parts.numHoles);
+    assert(table != NULL);
+    assert(allocEntries <= maxEntries);
+    assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
 
-    int idx = dvmIndirectRefToIndex(iref);
+    int idx = extractIndex(iref);
     if (idx < bottomIndex) {
         /* wrong segment */
         LOGV("Attempt to remove index outside index area (%d vs %d-%d)",
@@ -295,30 +231,31 @@
          * Top-most entry.  Scan up and consume holes.  No need to NULL
          * out the entry, since the test vs. topIndex will catch it.
          */
-        if (!checkEntry(pRef, iref, idx))
+        if (!checkEntry(iref, idx)) {
             return false;
-        updateSlotRemove(pRef, idx);
+        }
+        updateSlotRemove(idx);
 
 #ifndef NDEBUG
-        pRef->table[idx] = (Object*)0xd3d3d3d3;
+        table[idx] = (Object*)0xd3d3d3d3;
 #endif
 
         int numHoles =
-            pRef->segmentState.parts.numHoles - prevState.parts.numHoles;
+            segmentState.parts.numHoles - prevState.parts.numHoles;
         if (numHoles != 0) {
             while (--topIndex > bottomIndex && numHoles != 0) {
                 LOGV("+++ checking for hole at %d (cookie=0x%08x) val=%p",
-                    topIndex-1, cookie, pRef->table[topIndex-1]);
-                if (pRef->table[topIndex-1] != NULL)
+                    topIndex-1, cookie, table[topIndex-1]);
+                if (table[topIndex-1] != NULL)
                     break;
                 LOGV("+++ ate hole at %d", topIndex-1);
                 numHoles--;
             }
-            pRef->segmentState.parts.numHoles =
+            segmentState.parts.numHoles =
                 numHoles + prevState.parts.numHoles;
-            pRef->segmentState.parts.topIndex = topIndex;
+            segmentState.parts.topIndex = topIndex;
         } else {
-            pRef->segmentState.parts.topIndex = topIndex-1;
+            segmentState.parts.topIndex = topIndex-1;
             LOGV("+++ ate last entry %d", topIndex-1);
         }
     } else {
@@ -327,29 +264,27 @@
          * entry to prevent somebody from deleting it twice and screwing up
          * the hole count.
          */
-        if (pRef->table[idx] == NULL) {
+        if (table[idx] == NULL) {
             LOGV("--- WEIRD: removing null entry %d", idx);
             return false;
         }
-        if (!checkEntry(pRef, iref, idx))
+        if (!checkEntry(iref, idx)) {
             return false;
-        updateSlotRemove(pRef, idx);
+        }
+        updateSlotRemove(idx);
 
-        pRef->table[idx] = NULL;
-        pRef->segmentState.parts.numHoles++;
+        table[idx] = NULL;
+        segmentState.parts.numHoles++;
         LOGV("+++ left hole at %d, holes=%d",
-            idx, pRef->segmentState.parts.numHoles);
+            idx, segmentState.parts.numHoles);
     }
 
     return true;
 }
 
-/*
- * Return a type name, useful for debugging.
- */
-const char* dvmIndirectRefTypeName(IndirectRef iref)
+const char* indirectRefKindToString(IndirectRefKind kind)
 {
-    switch (dvmGetIndirectRefType(iref)) {
+    switch (kind) {
     case kIndirectKindInvalid:      return "invalid";
     case kIndirectKindLocal:        return "local";
     case kIndirectKindGlobal:       return "global";
@@ -358,11 +293,7 @@
     }
 }
 
-/*
- * Dump the contents of a IndirectRefTable to the log.
- */
-void dvmDumpIndirectRefTable(const IndirectRefTable* pRef, const char* descr)
+void IndirectRefTable::dump(const char* descr) const
 {
-    dvmDumpReferenceTableContents(pRef->table, dvmIndirectRefTableEntries(pRef),
-        descr);
+    dvmDumpReferenceTableContents(table, capacity(), descr);
 }