Add JNI app bug workarounds.

Specifically, this hands out direct pointers for all local references,
and lets you use a JNIEnv* on the wrong thread. This is off by default,
but enabled for apps that don't have ICS as their targetSdkVersion.

Bug: 4772166
Change-Id: I20c403a8e63481a35d579d2bd3b121c80ec08f89
diff --git a/vm/IndirectRefTable.cpp b/vm/IndirectRefTable.cpp
index fcf59af..6a50dab 100644
--- a/vm/IndirectRefTable.cpp
+++ b/vm/IndirectRefTable.cpp
@@ -194,6 +194,19 @@
     return true;
 }
 
+static int linearScan(IndirectRef iref, int bottomIndex, int topIndex, Object** table) {
+    for (int i = bottomIndex; i < topIndex; ++i) {
+        if (table[i] == reinterpret_cast<Object*>(iref)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+bool IndirectRefTable::contains(IndirectRef iref) const {
+    return linearScan(iref, 0, segmentState.parts.topIndex, table) != -1;
+}
+
 /*
  * Remove "obj" from "pRef".  We extract the table offset bits from "iref"
  * and zap the corresponding entry, leaving a hole if it's not at the top.
@@ -219,6 +232,17 @@
     assert(segmentState.parts.numHoles >= prevState.parts.numHoles);
 
     int idx = extractIndex(iref);
+    bool fakeDirectReferenceHack = false;
+
+    if (indirectRefKind(iref) == kIndirectKindInvalid && gDvmJni.workAroundAppJniBugs) {
+        idx = linearScan(iref, bottomIndex, topIndex, table);
+        fakeDirectReferenceHack = true;
+        if (idx == -1) {
+            LOGW("trying to work around app JNI bugs, but didn't find %p in table!", iref);
+            return false;
+        }
+    }
+
     if (idx < bottomIndex) {
         /* wrong segment */
         LOGV("Attempt to remove index outside index area (%d vs %d-%d)",
@@ -237,10 +261,9 @@
          * 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("remove", iref, idx)) {
+        if (fakeDirectReferenceHack == false && !checkEntry("remove", iref, idx)) {
             return false;
         }
-        updateSlotRemove(idx);
 
 #ifndef NDEBUG
         table[idx] = (Object*)0xd3d3d3d3;
@@ -274,10 +297,9 @@
             LOGV("--- WEIRD: removing null entry %d", idx);
             return false;
         }
-        if (!checkEntry("remove", iref, idx)) {
+        if (fakeDirectReferenceHack == false && !checkEntry("remove", iref, idx)) {
             return false;
         }
-        updateSlotRemove(idx);
 
         table[idx] = NULL;
         segmentState.parts.numHoles++;