summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Chartier <mathieuc@google.com>2014-12-11 18:43:48 -0800
committerMathieu Chartier <mathieuc@google.com>2014-12-12 12:08:16 -0800
commit9e2094f921b63582e84d65849b1c5c6dc4d22b44 (patch)
tree02613d533bdc382988b7fc70954c15c2ea4575aa
parent6b1497421c7c81cb9bf2ce077f1ef3d8ac24cfcb (diff)
downloadart-9e2094f921b63582e84d65849b1c5c6dc4d22b44.zip
art-9e2094f921b63582e84d65849b1c5c6dc4d22b44.tar.gz
art-9e2094f921b63582e84d65849b1c5c6dc4d22b44.tar.bz2
Add ReferenceQueue test
Also cleaned up reference queue. TODO: Add tests for missing functionality. Bug: 10808403 Change-Id: I182f9cb69022fe542ea9e53d4c6d35cff90af332
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--runtime/gc/reference_queue.cc19
-rw-r--r--runtime/gc/reference_queue.h17
-rw-r--r--runtime/gc/reference_queue_test.cc85
4 files changed, 111 insertions, 11 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 340304a..1347849 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -102,6 +102,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \
runtime/gc/accounting/card_table_test.cc \
runtime/gc/accounting/space_bitmap_test.cc \
runtime/gc/heap_test.cc \
+ runtime/gc/reference_queue_test.cc \
runtime/gc/space/dlmalloc_space_base_test.cc \
runtime/gc/space/dlmalloc_space_static_test.cc \
runtime/gc/space/dlmalloc_space_random_test.cc \
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index 4003524..f4efe3c 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -91,15 +91,30 @@ mirror::Reference* ReferenceQueue::DequeuePendingReference() {
void ReferenceQueue::Dump(std::ostream& os) const {
mirror::Reference* cur = list_;
os << "Reference starting at list_=" << list_ << "\n";
- while (cur != nullptr) {
+ if (cur == nullptr) {
+ return;
+ }
+ do {
mirror::Reference* pending_next = cur->GetPendingNext();
- os << "PendingNext=" << pending_next;
+ os << "Reference= " << cur << " PendingNext=" << pending_next;
if (cur->IsFinalizerReferenceInstance()) {
os << " Zombie=" << cur->AsFinalizerReference()->GetZombie();
}
os << "\n";
cur = pending_next;
+ } while (cur != list_);
+}
+
+size_t ReferenceQueue::GetLength() const {
+ size_t count = 0;
+ mirror::Reference* cur = list_;
+ if (cur != nullptr) {
+ do {
+ ++count;
+ cur = cur->GetPendingNext();
+ } while (cur != list_);
}
+ return count;
}
void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references,
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index 4ef8478..f7d89d0 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -56,12 +56,14 @@ class ReferenceQueue {
// overhead.
void EnqueueReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Enqueue a reference without checking that it is enqueable.
void EnqueuePendingReference(mirror::Reference* ref) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Dequeue the first reference (returns list_).
mirror::Reference* DequeuePendingReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Enqueues finalizer references with white referents. White referents are blackened, moved to the
- // zombie field, and the referent field is cleared.
+ // Enqueues finalizer references with white referents. White referents are blackened, moved to
+ // the zombie field, and the referent field is cleared.
void EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
IsHeapReferenceMarkedCallback* is_marked_callback,
MarkObjectCallback* mark_object_callback, void* arg)
@@ -73,24 +75,22 @@ class ReferenceQueue {
void ForwardSoftReferences(IsHeapReferenceMarkedCallback* preserve_callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Unlink the reference list clearing references objects with white referents. Cleared references
+ // Unlink the reference list clearing references objects with white referents. Cleared references
// registered to a reference queue are scheduled for appending by the heap worker thread.
void ClearWhiteReferences(ReferenceQueue* cleared_references,
IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void Dump(std::ostream& os) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void Dump(std::ostream& os) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ size_t GetLength() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsEmpty() const {
return list_ == nullptr;
}
-
void Clear() {
list_ = nullptr;
}
-
- mirror::Reference* GetList() {
+ mirror::Reference* GetList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return list_;
}
@@ -102,7 +102,6 @@ class ReferenceQueue {
// Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously
// calling AtomicEnqueueIfNotEnqueued.
Mutex* const lock_;
-
// The actual reference list. Only a root for the mark compact GC since it will be null for other
// GC types.
mirror::Reference* list_;
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
new file mode 100644
index 0000000..888c0d2
--- /dev/null
+++ b/runtime/gc/reference_queue_test.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_runtime_test.h"
+#include "reference_queue.h"
+#include "handle_scope-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace gc {
+
+class ReferenceQueueTest : public CommonRuntimeTest {};
+
+TEST_F(ReferenceQueueTest, EnqueueDequeue) {
+ Thread* self = Thread::Current();
+ StackHandleScope<20> hs(self);
+ Mutex lock("Reference queue lock");
+ ReferenceQueue queue(&lock);
+ ASSERT_TRUE(queue.IsEmpty());
+ ScopedObjectAccess soa(self);
+ ASSERT_EQ(queue.GetLength(), 0U);
+ auto ref_class = hs.NewHandle(
+ Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
+ NullHandle<mirror::ClassLoader>()));
+ ASSERT_TRUE(ref_class.Get() != nullptr);
+ auto ref1(hs.NewHandle(ref_class->AllocObject(self)->AsReference()));
+ ASSERT_TRUE(ref1.Get() != nullptr);
+ auto ref2(hs.NewHandle(ref_class->AllocObject(self)->AsReference()));
+ ASSERT_TRUE(ref2.Get() != nullptr);
+ // FIFO ordering.
+ queue.EnqueuePendingReference(ref1.Get());
+ ASSERT_TRUE(!queue.IsEmpty());
+ ASSERT_EQ(queue.GetLength(), 1U);
+ queue.EnqueuePendingReference(ref2.Get());
+ ASSERT_TRUE(!queue.IsEmpty());
+ ASSERT_EQ(queue.GetLength(), 2U);
+ ASSERT_EQ(queue.DequeuePendingReference(), ref2.Get());
+ ASSERT_TRUE(!queue.IsEmpty());
+ ASSERT_EQ(queue.GetLength(), 1U);
+ ASSERT_EQ(queue.DequeuePendingReference(), ref1.Get());
+ ASSERT_EQ(queue.GetLength(), 0U);
+ ASSERT_TRUE(queue.IsEmpty());
+}
+
+TEST_F(ReferenceQueueTest, Dump) {
+ Thread* self = Thread::Current();
+ StackHandleScope<20> hs(self);
+ Mutex lock("Reference queue lock");
+ ReferenceQueue queue(&lock);
+ ScopedObjectAccess soa(self);
+ queue.Dump(LOG(INFO));
+ auto weak_ref_class = hs.NewHandle(
+ Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
+ NullHandle<mirror::ClassLoader>()));
+ ASSERT_TRUE(weak_ref_class.Get() != nullptr);
+ auto finalizer_ref_class = hs.NewHandle(
+ Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/FinalizerReference;",
+ NullHandle<mirror::ClassLoader>()));
+ ASSERT_TRUE(finalizer_ref_class.Get() != nullptr);
+ auto ref1(hs.NewHandle(weak_ref_class->AllocObject(self)->AsReference()));
+ ASSERT_TRUE(ref1.Get() != nullptr);
+ auto ref2(hs.NewHandle(finalizer_ref_class->AllocObject(self)->AsReference()));
+ ASSERT_TRUE(ref2.Get() != nullptr);
+ queue.EnqueuePendingReference(ref1.Get());
+ queue.Dump(LOG(INFO));
+ queue.EnqueuePendingReference(ref2.Get());
+ queue.Dump(LOG(INFO));
+}
+
+} // namespace gc
+} // namespace art