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/class_linker.cc b/src/class_linker.cc
index 6ebc638..2c69651 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -474,16 +474,18 @@
   // as the types of the field can't be resolved prior to the runtime being
   // fully initialized
   Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;");
+  Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;");
   Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;");
 
+  Heap::SetWellKnownClasses(java_lang_ref_FinalizerReference, java_lang_ref_ReferenceQueue);
+
   Field* pendingNext = java_lang_ref_Reference->GetInstanceField(0);
   CHECK(pendingNext->GetName()->Equals("pendingNext"));
   CHECK_EQ(ResolveType(pendingNext->GetTypeIdx(), pendingNext), java_lang_ref_Reference);
 
   Field* queue = java_lang_ref_Reference->GetInstanceField(1);
   CHECK(queue->GetName()->Equals("queue"));
-  CHECK_EQ(ResolveType(queue->GetTypeIdx(), queue),
-           FindSystemClass("Ljava/lang/ref/ReferenceQueue;"));
+  CHECK_EQ(ResolveType(queue->GetTypeIdx(), queue), java_lang_ref_ReferenceQueue);
 
   Field* queueNext = java_lang_ref_Reference->GetInstanceField(2);
   CHECK(queueNext->GetName()->Equals("queueNext"));
@@ -2108,7 +2110,7 @@
   CHECK_EQ(num_fields == 0, fields == NULL);
 
   // we want a relatively stable order so that adding new fields
-  // minimizes distruption of C++ version such as Class and Method.
+  // minimizes disruption of C++ version such as Class and Method.
   std::deque<Field*> grouped_and_sorted_fields;
   for (size_t i = 0; i < num_fields; i++) {
     grouped_and_sorted_fields.push_back(fields->Get(i));
@@ -2175,6 +2177,15 @@
     current_field++;
   }
 
+  // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
+  if (instance && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
+    // We know there are no non-reference fields in the Reference classes, and we know
+    // that 'referent' is alphabetically last, so this is easy...
+    CHECK_EQ(num_reference_fields, num_fields);
+    CHECK(fields->Get(num_fields - 1)->GetName()->Equals("referent"));
+    --num_reference_fields;
+  }
+
 #ifndef NDEBUG
   // Make sure that all reference fields appear before
   // non-reference fields, and all double-wide fields are aligned.
@@ -2188,7 +2199,11 @@
                 << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
     }
     const Class* type = field->GetTypeDuringLinking();
-    if (type != NULL && type->IsPrimitive()) {
+    bool is_primitive = (type != NULL && type->IsPrimitive());
+    if (klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;") && field->GetName()->Equals("referent")) {
+      is_primitive = true; // We lied above, so we have to expect a lie here.
+    }
+    if (is_primitive) {
       if (!seen_non_ref) {
         seen_non_ref = true;
         DCHECK_EQ(num_reference_fields, i);
diff --git a/src/heap.cc b/src/heap.cc
index 92ebbd0..e69bc34 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -31,6 +31,9 @@
 
 HeapBitmap* Heap::live_bitmap_ = NULL;
 
+Class* Heap::java_lang_ref_FinalizerReference_ = NULL;
+Class* Heap::java_lang_ref_ReferenceQueue_ = NULL;
+
 MemberOffset Heap::reference_referent_offset_ = MemberOffset(0);
 MemberOffset Heap::reference_queue_offset_ = MemberOffset(0);
 MemberOffset Heap::reference_queueNext_offset_ = MemberOffset(0);
@@ -447,6 +450,7 @@
 
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   thread_list->SuspendAll();
+  Object* cleared_references = NULL;
   {
     MarkSweep mark_sweep;
 
@@ -473,10 +477,14 @@
     // TODO: swap bitmaps
 
     mark_sweep.Sweep();
+
+    cleared_references = mark_sweep.GetClearedReferences();
   }
 
   GrowForUtilization();
   thread_list->ResumeAll();
+
+  EnqueueClearedReferences(&cleared_references);
 }
 
 void Heap::WaitForConcurrentGcToComplete() {
@@ -501,4 +509,110 @@
   lock_->Unlock();
 }
 
+void Heap::SetWellKnownClasses(Class* java_lang_ref_FinalizerReference,
+    Class* java_lang_ref_ReferenceQueue) {
+  java_lang_ref_FinalizerReference_ = java_lang_ref_FinalizerReference;
+  java_lang_ref_ReferenceQueue_ = java_lang_ref_ReferenceQueue;
+  CHECK(java_lang_ref_FinalizerReference_ != NULL);
+  CHECK(java_lang_ref_ReferenceQueue_ != NULL);
+}
+
+void Heap::SetReferenceOffsets(MemberOffset reference_referent_offset,
+    MemberOffset reference_queue_offset,
+    MemberOffset reference_queueNext_offset,
+    MemberOffset reference_pendingNext_offset,
+    MemberOffset finalizer_reference_zombie_offset) {
+  reference_referent_offset_ = reference_referent_offset;
+  reference_queue_offset_ = reference_queue_offset;
+  reference_queueNext_offset_ = reference_queueNext_offset;
+  reference_pendingNext_offset_ = reference_pendingNext_offset;
+  finalizer_reference_zombie_offset_ = finalizer_reference_zombie_offset;
+  CHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
+  CHECK_NE(reference_queue_offset_.Uint32Value(), 0U);
+  CHECK_NE(reference_queueNext_offset_.Uint32Value(), 0U);
+  CHECK_NE(reference_pendingNext_offset_.Uint32Value(), 0U);
+  CHECK_NE(finalizer_reference_zombie_offset_.Uint32Value(), 0U);
+}
+
+Object* Heap::GetReferenceReferent(Object* reference) {
+  DCHECK(reference != NULL);
+  DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
+  return reference->GetFieldObject<Object*>(reference_referent_offset_, true);
+}
+
+void Heap::ClearReferenceReferent(Object* reference) {
+  DCHECK(reference != NULL);
+  DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
+  reference->SetFieldObject(reference_referent_offset_, NULL, true);
+}
+
+// Returns true if the reference object has not yet been enqueued.
+bool Heap::IsEnqueuable(const Object* ref) {
+  DCHECK(ref != NULL);
+  const Object* queue = ref->GetFieldObject<Object*>(reference_queue_offset_, false);
+  const Object* queue_next = ref->GetFieldObject<Object*>(reference_queueNext_offset_, false);
+  return (queue != NULL) && (queue_next == NULL);
+}
+
+void Heap::EnqueueReference(Object* ref, Object** cleared_reference_list) {
+  DCHECK(ref != NULL);
+  CHECK(ref->GetFieldObject<Object*>(reference_queue_offset_, false) != NULL);
+  CHECK(ref->GetFieldObject<Object*>(reference_queueNext_offset_, false) == NULL);
+  EnqueuePendingReference(ref, cleared_reference_list);
+}
+
+void Heap::EnqueuePendingReference(Object* ref, Object** list) {
+  DCHECK(ref != NULL);
+  DCHECK(list != NULL);
+
+  if (*list == NULL) {
+    ref->SetFieldObject(reference_pendingNext_offset_, ref, false);
+    *list = ref;
+  } else {
+    Object* head = (*list)->GetFieldObject<Object*>(reference_pendingNext_offset_, false);
+    ref->SetFieldObject(reference_pendingNext_offset_, head, false);
+    (*list)->SetFieldObject(reference_pendingNext_offset_, ref, false);
+  }
+}
+
+Object* Heap::DequeuePendingReference(Object** list) {
+  DCHECK(list != NULL);
+  DCHECK(*list != NULL);
+  Object* head = (*list)->GetFieldObject<Object*>(reference_pendingNext_offset_, false);
+  Object* ref;
+  if (*list == head) {
+    ref = *list;
+    *list = NULL;
+  } else {
+    Object* next = head->GetFieldObject<Object*>(reference_pendingNext_offset_, false);
+    (*list)->SetFieldObject(reference_pendingNext_offset_, next, false);
+    ref = head;
+  }
+  ref->SetFieldObject(reference_pendingNext_offset_, NULL, false);
+  return ref;
+}
+
+void Heap::AddFinalizerReference(Object* object) {
+  static Method* FinalizerReference_add =
+      java_lang_ref_FinalizerReference_->FindDirectMethod("add", "(Ljava/lang/Object;)V");
+  DCHECK(FinalizerReference_add != NULL);
+  Object* args[] = { object };
+  FinalizerReference_add->Invoke(Thread::Current(), NULL, reinterpret_cast<byte*>(&args), NULL);
+}
+
+void Heap::EnqueueClearedReferences(Object** cleared) {
+  DCHECK(cleared != NULL);
+  if (*cleared != NULL) {
+    static Method* ReferenceQueue_add =
+        java_lang_ref_ReferenceQueue_->FindDirectMethod("add", "(Ljava/lang/ref/Reference;)V");
+    DCHECK(ReferenceQueue_add != NULL);
+
+    Thread* self = Thread::Current();
+    ScopedThreadStateChange tsc(self, Thread::kRunnable);
+    Object* args[] = { *cleared };
+    ReferenceQueue_add->Invoke(self, NULL, reinterpret_cast<byte*>(&args), NULL);
+    *cleared = NULL;
+  }
+}
+
 }  // namespace art
diff --git a/src/heap.h b/src/heap.h
index 76e33b5..1eb3b16 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -112,37 +112,23 @@
     return mark_bitmap_;
   }
 
+  static void SetWellKnownClasses(Class* java_lang_ref_FinalizerReference,
+      Class* java_lang_ref_ReferenceQueue);
+
   static void SetReferenceOffsets(MemberOffset reference_referent_offset,
                                   MemberOffset reference_queue_offset,
                                   MemberOffset reference_queueNext_offset,
                                   MemberOffset reference_pendingNext_offset,
-                                  MemberOffset finalizer_reference_zombie_offset) {
-    CHECK_NE(reference_referent_offset.Uint32Value(), 0U);
-    CHECK_NE(reference_queue_offset.Uint32Value(), 0U);
-    CHECK_NE(reference_queueNext_offset.Uint32Value(), 0U);
-    CHECK_NE(reference_pendingNext_offset.Uint32Value(), 0U);
-    CHECK_NE(finalizer_reference_zombie_offset.Uint32Value(), 0U);
-    reference_referent_offset_ = reference_referent_offset;
-    reference_queue_offset_ = reference_queue_offset;
-    reference_queueNext_offset_ = reference_queueNext_offset;
-    reference_pendingNext_offset_ = reference_pendingNext_offset;
-    finalizer_reference_zombie_offset_ = finalizer_reference_zombie_offset;
-  }
+                                  MemberOffset finalizer_reference_zombie_offset);
 
-  static MemberOffset GetReferenceReferentOffset() {
-    DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
-    return reference_referent_offset_;
-  }
+  static Object* GetReferenceReferent(Object* reference);
+  static void ClearReferenceReferent(Object* reference);
 
-  static MemberOffset GetReferenceQueueOffset() {
-    DCHECK_NE(reference_queue_offset_.Uint32Value(), 0U);
-    return reference_queue_offset_;
-  }
-
-  static MemberOffset GetReferenceQueueNextOffset() {
-    DCHECK_NE(reference_queueNext_offset_.Uint32Value(), 0U);
-    return reference_queueNext_offset_;
-  }
+  // Returns true if the reference object has not yet been enqueued.
+  static bool IsEnqueuable(const Object* ref);
+  static void EnqueueReference(Object* ref, Object** list);
+  static void EnqueuePendingReference(Object* ref, Object** list);
+  static Object* DequeuePendingReference(Object** list);
 
   static MemberOffset GetReferencePendingNextOffset() {
     DCHECK_NE(reference_pendingNext_offset_.Uint32Value(), 0U);
@@ -174,11 +160,16 @@
 #endif
   }
 
+  static void AddFinalizerReference(Object* object);
+
  private:
   // Allocates uninitialized storage.
   static Object* AllocateLocked(size_t num_bytes);
   static Object* AllocateLocked(Space* space, size_t num_bytes);
 
+  // Pushes a list of cleared references out to the managed heap.
+  static void EnqueueClearedReferences(Object** cleared_references);
+
   static void RecordAllocationLocked(Space* space, const Object* object);
   static void RecordImageAllocations(Space* space);
 
@@ -215,6 +206,9 @@
   // free.
   static size_t num_objects_allocated_;
 
+  static Class* java_lang_ref_FinalizerReference_;
+  static Class* java_lang_ref_ReferenceQueue_;
+
   // offset of java.lang.ref.Reference.referent
   static MemberOffset reference_referent_offset_;
 
diff --git a/src/java_lang_Runtime.cc b/src/java_lang_Runtime.cc
index a3f4f49..a2bd399 100644
--- a/src/java_lang_Runtime.cc
+++ b/src/java_lang_Runtime.cc
@@ -30,8 +30,6 @@
 namespace {
 
 void Runtime_gc(JNIEnv*, jclass) {
-  UNIMPLEMENTED(WARNING);
-  return;
   Heap::CollectGarbage();
 }
 
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();
diff --git a/src/mark_sweep.h b/src/mark_sweep.h
index fe37cab..cf099ad 100644
--- a/src/mark_sweep.h
+++ b/src/mark_sweep.h
@@ -49,6 +49,10 @@
   // Sweeps unmarked objects to complete the garbage collection.
   void Sweep();
 
+  Object* GetClearedReferences() {
+    return cleared_reference_list_;
+  }
+
  private:
   // Returns true if the object has its bit set in the mark bitmap.
   bool IsMarked(const Object* object) const {
@@ -96,27 +100,10 @@
   // Recursively blackens objects on the mark stack.
   void ProcessMarkStack();
 
-  // Adds a reference to the tail of a circular queue of references.
-  static void EnqueuePendingReference(Object* ref, Object** list);
-
-  // Removes the reference at the head of a circular queue of
-  // references.
-  static Object* DequeuePendingReference(Object** list);
-
-  // Sets the referent field of a reference object to null.
-  static void ClearReference(Object* reference);
-
-  // Returns true if the reference object has not yet been enqueued.
-  static bool IsEnqueuable(const Object* ref);
-
-  void EnqueueReference(Object* ref);
-
   void EnqueueFinalizerReferences(Object** ref);
 
   void PreserveSomeSoftReferences(Object** ref);
 
-  void EnqueueClearedReferences(Object** cleared_references);
-
   void ClearWhiteReferences(Object** list);
 
   void ProcessReferences(Object** soft_references, bool clear_soft_references,
diff --git a/src/object.cc b/src/object.cc
index ce37470..35d8c8a 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -23,20 +23,6 @@
 
 namespace art {
 
-void Object::AddFinalizerReference() {
-  Thread* self = Thread::Current();
-
-  // TODO: cache these somewhere.
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Class* java_lang_ref_FinalizerReference = class_linker->FindSystemClass("Ljava/lang/ref/FinalizerReference;");
-  CHECK(java_lang_ref_FinalizerReference != NULL);
-  Method* m = java_lang_ref_FinalizerReference->FindDirectMethod("add", "(Ljava/lang/Object;)V");
-  CHECK(m != NULL);
-
-  LOG(INFO) << "Object::AddFinalizerReference invoking FinalizerReference.add for " << (void*) this;
-  m->Invoke(self, NULL, reinterpret_cast<byte*>(this), NULL);
-}
-
 Object* Object::Clone() {
   Class* c = GetClass();
   DCHECK(!c->IsClassClass());
@@ -57,7 +43,7 @@
   memcpy(dst_bytes + offset, src_bytes + offset, num_bytes - offset);
 
   if (c->IsFinalizable()) {
-    copy->AddFinalizerReference();
+    Heap::AddFinalizerReference(copy);
   }
 
   return copy;
diff --git a/src/object.h b/src/object.h
index ce1d144..6bfde65 100644
--- a/src/object.h
+++ b/src/object.h
@@ -298,9 +298,6 @@
     return down_cast<const Field*>(this);
   }
 
-  // If you're looking for SetFinalizable, this is the moral equivalent.
-  void AddFinalizerReference();
-
   bool IsReferenceInstance() const;
 
   bool IsWeakReferenceInstance() const;
diff --git a/src/object_bitmap.h b/src/object_bitmap.h
index 964c914..79b4027 100644
--- a/src/object_bitmap.h
+++ b/src/object_bitmap.h
@@ -69,7 +69,7 @@
   void Clear();
 
   bool Test(const Object* obj) {
-    CHECK(HasAddress(obj));
+    CHECK(HasAddress(obj)) << obj;
     CHECK(words_ != NULL);
     CHECK_GE((uintptr_t)obj, base_);
     if ((uintptr_t)obj <= max_) {
diff --git a/src/thread.cc b/src/thread.cc
index 78c877d..90c172e 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -70,7 +70,7 @@
 static void ObjectInitFromCode(Object* o) {
   Class* c = o->GetClass();
   if (c->IsFinalizable()) {
-    o->AddFinalizerReference();
+    Heap::AddFinalizerReference(o);
   }
   /*
    * NOTE: once debugger/profiler support is added, we'll need to check