Eliminate pointer tagging on the reference operation queue.

Tags are unconditionally added before references are added to the
reference queue.  This tag is checked when a reference is removed from
the queue and subsequently cleared.  There are no other observers of
this tag and so it is equivalent to not tag the reference in the first
place.  The original intent may have been to tag the references in
different ways.  Removing this code simplifies reference tracing.

Change-Id: Idb18929e601acdd049b4a92ebf588f3f5febb75c
diff --git a/vm/alloc/Copying.c b/vm/alloc/Copying.c
index 797b178..c1b4b70 100644
--- a/vm/alloc/Copying.c
+++ b/vm/alloc/Copying.c
@@ -1029,24 +1029,10 @@
  */
 static void enqueueReference(const Object *ref)
 {
-    LargeHeapRefTable **table;
-    Object *op;
-
-    assert(((uintptr_t)ref & 3) == 0);
-    assert((WORKER_ENQUEUE & ~3) == 0);
+    assert(ref != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
-    /*
-     * Set the enqueue bit in the bottom of the pointer.  Assumes that
-     * objects are 8-byte aligned.
-     *
-     * Note that we are adding the *Reference* (which is by definition
-     * already black at this point) to this list; we're not adding the
-     * referent (which has already been cleared).
-     */
-    table = &gDvm.gcHeap->referenceOperations;
-    op = (Object *)((uintptr_t)ref | WORKER_ENQUEUE);
-    if (!dvmHeapAddRefToLargeTable(table, op)) {
+    if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
         LOGE("no room for any more reference operations");
         dvmAbort();
     }
@@ -1571,18 +1557,12 @@
     }
 }
 
-static void scavengeLargeHeapRefTable(LargeHeapRefTable *table, bool stripLowBits)
+static void scavengeLargeHeapRefTable(LargeHeapRefTable *table)
 {
     for (; table != NULL; table = table->next) {
         Object **ref = table->refs.table;
         for (; ref < table->refs.nextEntry; ++ref) {
-            if (stripLowBits) {
-                Object *obj = (Object *)((uintptr_t)*ref & ~3);
-                scavengeReference(&obj);
-                *ref = (Object *)((uintptr_t)obj | ((uintptr_t)*ref & 3));
-            } else {
-                scavengeReference(ref);
-            }
+            scavengeReference(ref);
         }
     }
 }
@@ -2249,10 +2229,10 @@
     scavengeThreadList();
 
     LOG_SCAV("Scavenging gDvm.gcHeap->referenceOperations");
-    scavengeLargeHeapRefTable(gcHeap->referenceOperations, true);
+    scavengeLargeHeapRefTable(gcHeap->referenceOperations);
 
     LOG_SCAV("Scavenging gDvm.gcHeap->pendingFinalizationRefs");
-    scavengeLargeHeapRefTable(gcHeap->pendingFinalizationRefs, false);
+    scavengeLargeHeapRefTable(gcHeap->pendingFinalizationRefs);
 
     LOG_SCAV("Scavenging random global stuff");
     scavengeReference(&gDvm.outOfMemoryObj);
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index 32b4d3b..dcca837 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -190,30 +190,11 @@
 
     assert(op != NULL);
 
-    obj = NULL;
-
     dvmLockMutex(&gDvm.heapWorkerListLock);
 
-    /* We must handle reference operations before finalizations.
-     * If:
-     *     a) Someone subclasses WeakReference and overrides clear()
-     *     b) A reference of this type is the last reference to
-     *        a finalizable object
-     * then we need to guarantee that the overridden clear() is called
-     * on the reference before finalize() is called on the referent.
-     * Both of these operations will always be scheduled at the same
-     * time, so handling reference operations first will guarantee
-     * the required order.
-     */
     obj = dvmHeapGetNextObjectFromLargeTable(&gcHeap->referenceOperations);
     if (obj != NULL) {
-        uintptr_t workBits;
-
-        workBits = (uintptr_t)obj & WORKER_ENQUEUE;
-        assert(workBits != 0);
-        obj = (Object *)((uintptr_t)obj & ~WORKER_ENQUEUE);
-
-        *op = workBits;
+        *op = WORKER_ENQUEUE;
     } else {
         obj = dvmHeapGetNextObjectFromLargeTable(
                 &gcHeap->pendingFinalizationRefs);
@@ -225,9 +206,6 @@
     if (obj != NULL) {
         /* Don't let the GC collect the object until the
          * worker thread is done with it.
-         *
-         * This call is safe;  it uses thread-local storage
-         * and doesn't acquire any locks.
          */
         dvmAddTrackedAlloc(obj, NULL);
     }
diff --git a/vm/alloc/HeapTable.c b/vm/alloc/HeapTable.c
index d9077ea..e9f2729 100644
--- a/vm/alloc/HeapTable.c
+++ b/vm/alloc/HeapTable.c
@@ -183,25 +183,15 @@
     return obj;
 }
 
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table, bool stripLowBits)
+void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table)
 {
     while (table != NULL) {
         Object **ref, **lastRef;
 
         ref = table->refs.table;
         lastRef = table->refs.nextEntry;
-        if (stripLowBits) {
-            /* This case is used for marking reference objects that
-             * are still waiting for the heap worker thread to push
-             * them onto their reference queue.
-             */
-            while (ref < lastRef) {
-                dvmMarkObjectNonNull((Object *)((uintptr_t)*ref++ & ~3));
-            }
-        } else {
-            while (ref < lastRef) {
-                dvmMarkObjectNonNull(*ref++);
-            }
+        while (ref < lastRef) {
+            dvmMarkObjectNonNull(*ref++);
         }
         table = table->next;
     }
diff --git a/vm/alloc/HeapTable.h b/vm/alloc/HeapTable.h
index e994e25..55851b9 100644
--- a/vm/alloc/HeapTable.h
+++ b/vm/alloc/HeapTable.h
@@ -32,7 +32,7 @@
 void dvmHeapFreeLargeTable(LargeHeapRefTable *table);
 void dvmHeapHeapTableFree(void *ptr);
 bool dvmHeapAddRefToLargeTable(LargeHeapRefTable **tableP, Object *ref);
-void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table, bool stripLowBits);
+void dvmHeapMarkLargeTableRefs(LargeHeapRefTable *table);
 bool dvmHeapAddTableToLargeTable(LargeHeapRefTable **tableP,
         HeapRefTable *refs);
 Object *dvmHeapGetNextObjectFromLargeTable(LargeHeapRefTable **pTable);
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index a671118..18c5aae 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -275,15 +275,14 @@
             assert(method->clazz != gDvm.classJavaLangObject);
             callMethod(self, obj, method);
         } else {
-            if (op & WORKER_ENQUEUE) {
-                assert(dvmGetFieldObject(
-                           obj, gDvm.offJavaLangRefReference_queue) != NULL);
-                assert(dvmGetFieldObject(
-                           obj, gDvm.offJavaLangRefReference_queueNext) == NULL);
-                numReferencesEnqueued++;
-                callMethod(self, obj,
-                        gDvm.methJavaLangRefReference_enqueueInternal);
-            }
+            assert(op == WORKER_ENQUEUE);
+            assert(dvmGetFieldObject(
+                       obj, gDvm.offJavaLangRefReference_queue) != NULL);
+            assert(dvmGetFieldObject(
+                       obj, gDvm.offJavaLangRefReference_queueNext) == NULL);
+            numReferencesEnqueued++;
+            callMethod(self, obj,
+                       gDvm.methJavaLangRefReference_enqueueInternal);
         }
 
         /* Let the GC collect the object.
diff --git a/vm/alloc/HeapWorker.h b/vm/alloc/HeapWorker.h
index 2734aef..45587ff 100644
--- a/vm/alloc/HeapWorker.h
+++ b/vm/alloc/HeapWorker.h
@@ -76,11 +76,7 @@
  */
 typedef enum HeapWorkerOperation {
     WORKER_FINALIZE = 0,
-
-    /* Required: WORKER_ENQUEUE <= (4-1)
-     * This value will be stuffed in the low bits of a pointer.
-     */
-    WORKER_ENQUEUE = (1<<0),
+    WORKER_ENQUEUE = 1,
 } HeapWorkerOperation;
 
 /*
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index 865e154..6e8dc79 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -242,12 +242,12 @@
     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_REFERENCE_CLEANUP, 0);
 
     LOG_SCAN("pending reference operations\n");
-    dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations, true);
+    dvmHeapMarkLargeTableRefs(gcHeap->referenceOperations);
 
     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_FINALIZING, 0);
 
     LOG_SCAN("pending finalizations\n");
-    dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs, false);
+    dvmHeapMarkLargeTableRefs(gcHeap->pendingFinalizationRefs);
 
     HPROF_SET_GC_SCAN_STATE(HPROF_ROOT_DEBUGGER, 0);
 
@@ -597,24 +597,10 @@
  */
 static void enqueueReference(Object *ref)
 {
-    LargeHeapRefTable **table;
-    Object *op;
-
-    assert(((uintptr_t)ref & 3) == 0);
-    assert((WORKER_ENQUEUE & ~3) == 0);
+    assert(ref != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queue) != NULL);
     assert(dvmGetFieldObject(ref, gDvm.offJavaLangRefReference_queueNext) == NULL);
-    /* Stuff the enqueue bit in the bottom of the pointer.
-     * Assumes that objects are 8-byte aligned.
-     *
-     * Note that we are adding the *Reference* (which
-     * is by definition already marked at this point) to
-     * this list; we're not adding the referent (which
-     * has already been cleared).
-     */
-    table = &gDvm.gcHeap->referenceOperations;
-    op = (Object *)((uintptr_t)ref | WORKER_ENQUEUE);
-    if (!dvmHeapAddRefToLargeTable(table, op)) {
+    if (!dvmHeapAddRefToLargeTable(&gDvm.gcHeap->referenceOperations, ref)) {
         LOGE_HEAP("enqueueReference(): no room for any more "
                   "reference operations\n");
         dvmAbort();
diff --git a/vm/alloc/Verify.c b/vm/alloc/Verify.c
index 3cf0818..0353c9c 100644
--- a/vm/alloc/Verify.c
+++ b/vm/alloc/Verify.c
@@ -23,7 +23,7 @@
 /*
  * Helper routine for verifyRefernce that masks low-tag bits before
  * applying verification checks.  TODO: eliminate the use of low-tag
- * bits and move this code into verfiyReference.
+ * bits and move this code into verifyReference.
  */
 static void verifyReferenceUnmask(const void *addr, uintptr_t mask)
 {
@@ -131,29 +131,13 @@
 }
 
 /*
- * Applies the verify routine to a heap worker reference operation.
- */
-static void verifyReferenceOperation(const void *arg)
-{
-    assert(arg != NULL);
-    verifyReferenceUnmask(arg, 0x3);
-}
-
-/*
  * Verifies a large heap reference table.  These objects are list
  * heads.  As such, it is valid for table to be NULL.
  */
-static void verifyLargeHeapRefTable(LargeHeapRefTable *table,
-                                    void (*callback)(const void *arg))
+static void verifyLargeHeapRefTable(const LargeHeapRefTable *table)
 {
-    Object **ref;
-
-    assert(callback != NULL);
     for (; table != NULL; table = table->next) {
-        for (ref = table->refs.table; ref < table->refs.nextEntry; ++ref) {
-            assert(ref != NULL);
-            (*callback)(ref);
-        }
+        verifyReferenceTable(&table->refs);
     }
 }
 
@@ -273,10 +257,8 @@
     verifyHashTable(gDvm.internedStrings, verifyStringReference);
     verifyReferenceTable(&gDvm.jniGlobalRefTable);
     verifyReferenceTable(&gDvm.jniPinRefTable);
-    verifyLargeHeapRefTable(gDvm.gcHeap->referenceOperations,
-                            verifyReferenceOperation);
-    verifyLargeHeapRefTable(gDvm.gcHeap->pendingFinalizationRefs,
-                            verifyReference);
+    verifyLargeHeapRefTable(gDvm.gcHeap->referenceOperations);
+    verifyLargeHeapRefTable(gDvm.gcHeap->pendingFinalizationRefs);
     verifyThreads();
     /* TODO: verify cached global references. */
 }