diff options
author | Hiroshi Yamauchi <yamauchi@google.com> | 2015-09-10 16:01:30 -0700 |
---|---|---|
committer | Hiroshi Yamauchi <yamauchi@google.com> | 2015-09-14 10:15:08 -0700 |
commit | 70c08d3c913ce2150cd620ea87b919f8eb5bd953 (patch) | |
tree | 7390f7bc8cfbf3ada1f387e470e51c4ff7531145 | |
parent | 2d06e08d25bbf8eff1de945736a60810009e59ad (diff) | |
download | art-70c08d3c913ce2150cd620ea87b919f8eb5bd953.tar.gz art-70c08d3c913ce2150cd620ea87b919f8eb5bd953.tar.bz2 art-70c08d3c913ce2150cd620ea87b919f8eb5bd953.zip |
Fix the DequeuePendingReference crash.
In DequeuePendingReference, acknowledge a black/white Reference object
in the queue if its referent was marked right after it's enqueued.
Bug: 12687968
Bug: 23896462
Change-Id: I33c802e04e1688a54a70ad3935628e3853c46e44
-rw-r--r-- | runtime/gc/collector/concurrent_copying.cc | 7 | ||||
-rw-r--r-- | runtime/gc/reference_queue.cc | 39 |
2 files changed, 34 insertions, 12 deletions
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 57af95940d..4cbcdc5d42 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -1073,9 +1073,14 @@ void ConcurrentCopying::ProcessMarkStackRef(mirror::Object* to_ref) { if (to_ref->GetClass<kVerifyNone, kWithoutReadBarrier>()->IsTypeOfReferenceClass() && to_ref->AsReference()->GetReferent<kWithoutReadBarrier>() != nullptr && !IsInToSpace(to_ref->AsReference()->GetReferent<kWithoutReadBarrier>())) { - // Leave References gray so that GetReferent() will trigger RB. + // Leave this Reference gray in the queue so that GetReferent() will trigger a read barrier. We + // will change it to black or white later in ReferenceQueue::DequeuePendingReference(). CHECK(to_ref->AsReference()->IsEnqueued()) << "Left unenqueued ref gray " << to_ref; } else { + // We may occasionally leave a Reference black or white in the queue if its referent happens to + // be concurrently marked after the Scan() call above has enqueued the Reference, in which case + // the above IsInToSpace() evaluates to true and we change the color from gray to black or white + // here in this else block. #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER if (kUseBakerReadBarrier) { if (region_space_->IsInToSpace(to_ref)) { diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc index f5054289e3..0c0ab6d212 100644 --- a/runtime/gc/reference_queue.cc +++ b/runtime/gc/reference_queue.cc @@ -89,19 +89,36 @@ mirror::Reference* ReferenceQueue::DequeuePendingReference() { Heap* heap = Runtime::Current()->GetHeap(); if (kUseBakerOrBrooksReadBarrier && heap->CurrentCollectorType() == kCollectorTypeCC && heap->ConcurrentCopyingCollector()->IsActive()) { - // Clear the gray ptr we left in ConcurrentCopying::ProcessMarkStack(). - // We don't want to do this when the zygote compaction collector (SemiSpace) is running. + // Change the gray ptr we left in ConcurrentCopying::ProcessMarkStackRef() to black or white. + // We check IsActive() above because we don't want to do this when the zygote compaction + // collector (SemiSpace) is running. CHECK(ref != nullptr); - CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::GrayPtr()) - << "ref=" << ref << " rb_ptr=" << ref->GetReadBarrierPointer(); - if (heap->ConcurrentCopyingCollector()->RegionSpace()->IsInToSpace(ref)) { - // Moving objects. - ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(), ReadBarrier::WhitePtr()); - CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::WhitePtr()); + collector::ConcurrentCopying* concurrent_copying = heap->ConcurrentCopyingCollector(); + const bool is_moving = concurrent_copying->RegionSpace()->IsInToSpace(ref); + if (ref->GetReadBarrierPointer() == ReadBarrier::GrayPtr()) { + if (is_moving) { + ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(), ReadBarrier::WhitePtr()); + CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::WhitePtr()); + } else { + ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(), ReadBarrier::BlackPtr()); + CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::BlackPtr()); + } } else { - // Non-moving objects. - ref->AtomicSetReadBarrierPointer(ReadBarrier::GrayPtr(), ReadBarrier::BlackPtr()); - CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::BlackPtr()); + // In ConcurrentCopying::ProcessMarkStackRef() we may leave a black or white Reference in the + // queue and find it here, which is OK. Check that the color makes sense depending on whether + // the Reference is moving or not and that the referent has been marked. + if (is_moving) { + CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::WhitePtr()) + << "ref=" << ref << " rb_ptr=" << ref->GetReadBarrierPointer(); + } else { + CHECK_EQ(ref->GetReadBarrierPointer(), ReadBarrier::BlackPtr()) + << "ref=" << ref << " rb_ptr=" << ref->GetReadBarrierPointer(); + } + mirror::Object* referent = ref->GetReferent<kWithoutReadBarrier>(); + CHECK(referent != nullptr) << "Reference should not have been enqueued if referent is null"; + CHECK(concurrent_copying->IsInToSpace(referent)) + << "ref=" << ref << " rb_ptr=" << ref->GetReadBarrierPointer() + << " referent=" << referent; } } return ref; |