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