Implement finalization.

Also make System.gc no longer a no-op. This replaces some of the
MemberOffsets exposed by Heap with intention-revealing functions
that we'll want to share between all the actual GC implementations,
but there's still more to be done.

Change-Id: I57ba26c0416fbbfe20142b7b6e27108684add7f9
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 4965692..ae6edea 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -183,9 +183,7 @@
 // Scans static storage on a Class.
 void MarkSweep::ScanStaticFields(const Class* klass) {
   DCHECK(klass != NULL);
-  ScanFields(klass,
-             klass->GetReferenceStaticOffsets(),
-             true);
+  ScanFields(klass, klass->GetReferenceStaticOffsets(), true);
 }
 
 void MarkSweep::ScanFields(const Object* obj,
@@ -266,39 +264,6 @@
   }
 }
 
-void MarkSweep::EnqueuePendingReference(Object* ref, Object** list) {
-  DCHECK(ref != NULL);
-  DCHECK(list != NULL);
-
-  MemberOffset offset = Heap::GetReferencePendingNextOffset();
-  if (*list == NULL) {
-    ref->SetFieldObject(offset, ref, false);
-    *list = ref;
-  } else {
-    Object* head = (*list)->GetFieldObject<Object*>(offset, false);
-    ref->SetFieldObject(offset, head, false);
-    (*list)->SetFieldObject(offset, ref, false);
-  }
-}
-
-Object* MarkSweep::DequeuePendingReference(Object** list) {
-  DCHECK(list != NULL);
-  DCHECK(*list != NULL);
-  MemberOffset offset = Heap::GetReferencePendingNextOffset();
-  Object* head = (*list)->GetFieldObject<Object*>(offset, false);
-  Object* ref;
-  if (*list == head) {
-    ref = *list;
-    *list = NULL;
-  } else {
-    Object* next = head->GetFieldObject<Object*>(offset, false);
-    (*list)->SetFieldObject(offset, next, false);
-    ref = head;
-  }
-  ref->SetFieldObject(offset, NULL, false);
-  return ref;
-}
-
 // Process the "referent" field in a java.lang.ref.Reference.  If the
 // referent has not yet been marked, put it on the appropriate list in
 // the gcHeap for later processing.
@@ -308,7 +273,7 @@
   DCHECK(klass != NULL);
   DCHECK(klass->IsReferenceClass());
   Object* pending = obj->GetFieldObject<Object*>(Heap::GetReferencePendingNextOffset(), false);
-  Object* referent = obj->GetFieldObject<Object*>(Heap::GetReferenceReferentOffset(), false);
+  Object* referent = Heap::GetReferenceReferent(obj);
   if (pending == NULL && referent != NULL && !IsMarked(referent)) {
     Object** list = NULL;
     if (klass->IsSoftReferenceClass()) {
@@ -321,13 +286,13 @@
       list = &phantom_reference_list_;
     }
     DCHECK(list != NULL);
-    EnqueuePendingReference(obj, list);
+    Heap::EnqueuePendingReference(obj, list);
   }
 }
 
 // Scans the header and field references of a data object.  If the
 // scanned object is a reference subclass, it is scheduled for later
-// processing
+// processing.
 void MarkSweep::ScanOther(const Object* obj) {
   DCHECK(obj != NULL);
   Class* klass = obj->GetClass();
@@ -367,27 +332,6 @@
   ProcessMarkStack();
 }
 
-void MarkSweep::ClearReference(Object* ref) {
-  DCHECK(ref != NULL);
-  ref->SetFieldObject(Heap::GetReferenceReferentOffset(), NULL, false);
-}
-
-bool MarkSweep::IsEnqueuable(const Object* ref) {
-  DCHECK(ref != NULL);
-  const Object* queue =
-      ref->GetFieldObject<Object*>(Heap::GetReferenceQueueOffset(), false);
-  const Object* queue_next =
-      ref->GetFieldObject<Object*>(Heap::GetReferenceQueueNextOffset(), false);
-  return (queue != NULL) && (queue_next == NULL);
-}
-
-void MarkSweep::EnqueueReference(Object* ref) {
-  DCHECK(ref != NULL);
-  CHECK(ref->GetFieldObject<Object*>(Heap::GetReferenceQueueOffset(), false) != NULL);
-  CHECK(ref->GetFieldObject<Object*>(Heap::GetReferenceQueueNextOffset(), false) == NULL);
-  EnqueuePendingReference(ref, &cleared_reference_list_);
-}
-
 // Walks the reference list marking any references subject to the
 // reference clearing policy.  References with a black referent are
 // removed from the list.  References with white referents biased
@@ -397,8 +341,8 @@
   Object* clear = NULL;
   size_t counter = 0;
   while (*list != NULL) {
-    Object* ref = DequeuePendingReference(list);
-    Object* referent = ref->GetFieldObject<Object*>(Heap::GetReferenceReferentOffset(), false);
+    Object* ref = Heap::DequeuePendingReference(list);
+    Object* referent = Heap::GetReferenceReferent(ref);
     if (referent == NULL) {
       // Referent was cleared by the user during marking.
       continue;
@@ -411,7 +355,7 @@
     }
     if (!is_marked) {
       // Referent is white, queue it for clearing.
-      EnqueuePendingReference(ref, &clear);
+      Heap::EnqueuePendingReference(ref, &clear);
     }
   }
   *list = clear;
@@ -425,15 +369,14 @@
 // scheduled for appending by the heap worker thread.
 void MarkSweep::ClearWhiteReferences(Object** list) {
   DCHECK(list != NULL);
-  MemberOffset offset = Heap::GetReferenceReferentOffset();
   while (*list != NULL) {
-    Object* ref = DequeuePendingReference(list);
-    Object* referent = ref->GetFieldObject<Object*>(offset, false);
+    Object* ref = Heap::DequeuePendingReference(list);
+    Object* referent = Heap::GetReferenceReferent(ref);
     if (referent != NULL && !IsMarked(referent)) {
       // Referent is white, clear it.
-      ClearReference(ref);
-      if (IsEnqueuable(ref)) {
-        EnqueueReference(ref);
+      Heap::ClearReferenceReferent(ref);
+      if (Heap::IsEnqueuable(ref)) {
+        Heap::EnqueueReference(ref, &cleared_reference_list_);
       }
     }
   }
@@ -445,19 +388,18 @@
 // referent field is cleared.
 void MarkSweep::EnqueueFinalizerReferences(Object** list) {
   DCHECK(list != NULL);
-  MemberOffset referent_offset = Heap::GetReferenceReferentOffset();
   MemberOffset zombie_offset = Heap::GetFinalizerReferenceZombieOffset();
   bool has_enqueued = false;
   while (*list != NULL) {
-    Object* ref = DequeuePendingReference(list);
-    Object* referent = ref->GetFieldObject<Object*>(referent_offset, false);
+    Object* ref = Heap::DequeuePendingReference(list);
+    Object* referent = Heap::GetReferenceReferent(ref);
     if (referent != NULL && !IsMarked(referent)) {
       MarkObject(referent);
       // If the referent is non-null the reference must queuable.
-      DCHECK(IsEnqueuable(ref));
+      DCHECK(Heap::IsEnqueuable(ref));
       ref->SetFieldObject(zombie_offset, referent, false);
-      ClearReference(ref);
-      EnqueueReference(ref);
+      Heap::ClearReferenceReferent(ref);
+      Heap::EnqueueReference(ref, &cleared_reference_list_);
       has_enqueued = true;
     }
   }
@@ -507,22 +449,6 @@
   DCHECK(*phantom_references == NULL);
 }
 
-// Pushes a list of cleared references out to the managed heap.
-void MarkSweep::EnqueueClearedReferences(Object** cleared) {
-  DCHECK(cleared != NULL);
-  if (*cleared != NULL) {
-    Thread* self = Thread::Current();
-    DCHECK(self != NULL);
-    // TODO: Method* m = gDvm.methJavaLangRefReferenceQueueAdd;
-    // DCHECK(m != NULL);
-    // Object* reference = *cleared;
-    // args = {reference}
-    // TODO: m->Invoke(self, NULL, args, NULL);
-    UNIMPLEMENTED(FATAL);
-    *cleared = NULL;
-  }
-}
-
 MarkSweep::~MarkSweep() {
   delete mark_stack_;
   mark_bitmap_->Clear();