8258142: Simplify G1RedirtyCardsQueue

Separate local redirty qset from redirty queue.

Reviewed-by: tschatzl, iwalulya
diff --git a/src/hotspot/share/gc/g1/g1EvacFailure.cpp b/src/hotspot/share/gc/g1/g1EvacFailure.cpp
index 7c85024..0d2175e 100644
--- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp
+++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp
@@ -199,6 +199,7 @@
   G1CollectedHeap* _g1h;
   uint _worker_id;
 
+  G1RedirtyCardsLocalQueueSet _rdc_local_qset;
   G1RedirtyCardsQueue _rdcq;
   UpdateLogBuffersDeferred _log_buffer_cl;
 
@@ -206,10 +207,16 @@
   RemoveSelfForwardPtrHRClosure(G1RedirtyCardsQueueSet* rdcqs, uint worker_id) :
     _g1h(G1CollectedHeap::heap()),
     _worker_id(worker_id),
-    _rdcq(rdcqs),
+    _rdc_local_qset(rdcqs),
+    _rdcq(&_rdc_local_qset),
     _log_buffer_cl(&_rdcq) {
   }
 
+  ~RemoveSelfForwardPtrHRClosure() {
+    _rdcq.flush();
+    _rdc_local_qset.flush();
+  }
+
   size_t remove_self_forward_ptr_by_walking_hr(HeapRegion* hr,
                                                bool during_concurrent_start) {
     RemoveSelfForwardPtrObjClosure rspc(hr,
diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
index c9ca7da..b9221ba 100644
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
@@ -58,7 +58,8 @@
                                            size_t optional_cset_length)
   : _g1h(g1h),
     _task_queue(g1h->task_queue(worker_id)),
-    _rdcq(rdcqs),
+    _rdc_local_qset(rdcqs),
+    _rdcq(&_rdc_local_qset),
     _ct(g1h->card_table()),
     _closures(NULL),
     _plab_allocator(NULL),
@@ -114,6 +115,7 @@
 
 size_t G1ParScanThreadState::flush(size_t* surviving_young_words) {
   _rdcq.flush();
+  _rdc_local_qset.flush();
   flush_numa_stats();
   // Update allocation statistics.
   _plab_allocator->flush_and_retire_stats();
diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
index 8b1c1b6..784b3b3 100644
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
@@ -48,6 +48,7 @@
 class G1ParScanThreadState : public CHeapObj<mtGC> {
   G1CollectedHeap* _g1h;
   G1ScannerTasksQueue* _task_queue;
+  G1RedirtyCardsLocalQueueSet _rdc_local_qset;
   G1RedirtyCardsQueue _rdcq;
   G1CardTable* _ct;
   G1EvacuationRootClosures* _closures;
diff --git a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp
index b62c236..d03c15b 100644
--- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,19 +30,21 @@
 
 // G1RedirtyCardsQueueBase::LocalQSet
 
-G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) :
+G1RedirtyCardsLocalQueueSet::G1RedirtyCardsLocalQueueSet(G1RedirtyCardsQueueSet* shared_qset) :
   PtrQueueSet(shared_qset->allocator()),
   _shared_qset(shared_qset),
   _buffers()
 {}
 
-G1RedirtyCardsQueueBase::LocalQSet::~LocalQSet() {
+#ifdef ASSERT
+G1RedirtyCardsLocalQueueSet::~G1RedirtyCardsLocalQueueSet() {
   assert(_buffers._head == NULL, "unflushed qset");
   assert(_buffers._tail == NULL, "invariant");
   assert(_buffers._entry_count == 0, "invariant");
 }
+#endif // ASSERT
 
-void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* node) {
+void G1RedirtyCardsLocalQueueSet::enqueue_completed_buffer(BufferNode* node) {
   _buffers._entry_count += buffer_size() - node->index();
   node->set_next(_buffers._head);
   _buffers._head = node;
@@ -51,26 +53,22 @@
   }
 }
 
-G1BufferNodeList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
-  G1BufferNodeList result = _buffers;
+void G1RedirtyCardsLocalQueueSet::flush() {
+  _shared_qset->add_bufferlist(_buffers);
   _buffers = G1BufferNodeList();
-  return result;
-}
-
-void G1RedirtyCardsQueueBase::LocalQSet::flush() {
-  _shared_qset->merge_bufferlist(this);
 }
 
 // G1RedirtyCardsQueue
 
-G1RedirtyCardsQueue::G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset) :
-  G1RedirtyCardsQueueBase(qset), // Init _local_qset before passing to PtrQueue.
-  PtrQueue(&_local_qset, true /* active (always) */)
+G1RedirtyCardsQueue::G1RedirtyCardsQueue(G1RedirtyCardsLocalQueueSet* qset) :
+  PtrQueue(qset, true /* always active */)
 {}
 
+#ifdef ASSERT
 G1RedirtyCardsQueue::~G1RedirtyCardsQueue() {
-  flush();
+  assert(is_empty(), "unflushed queue");
 }
+#endif // ASSERT
 
 void G1RedirtyCardsQueue::handle_completed_buffer() {
   enqueue_completed_buffer();
@@ -78,7 +76,6 @@
 
 void G1RedirtyCardsQueue::flush() {
   flush_impl();
-  _local_qset.flush();
 }
 
 // G1RedirtyCardsQueueSet
@@ -134,13 +131,12 @@
   update_tail(node);
 }
 
-void G1RedirtyCardsQueueSet::merge_bufferlist(LocalQSet* src) {
+void G1RedirtyCardsQueueSet::add_bufferlist(const G1BufferNodeList& buffers) {
   assert(_collecting, "precondition");
-  const G1BufferNodeList from = src->take_all_completed_buffers();
-  if (from._head != NULL) {
-    assert(from._tail != NULL, "invariant");
-    Atomic::add(&_entry_count, from._entry_count);
-    _list.prepend(*from._head, *from._tail);
-    update_tail(from._tail);
+  if (buffers._head != NULL) {
+    assert(buffers._tail != NULL, "invariant");
+    Atomic::add(&_entry_count, buffers._entry_count);
+    _list.prepend(*buffers._head, *buffers._tail);
+    update_tail(buffers._tail);
   }
 }
diff --git a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
index 7a4efa1..2a0d763 100644
--- a/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
+++ b/src/hotspot/share/gc/g1/g1RedirtyCardsQueue.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,56 +27,36 @@
 
 #include "gc/g1/g1BufferNodeList.hpp"
 #include "gc/shared/ptrQueue.hpp"
-#include "memory/allocation.hpp"
 #include "memory/padded.hpp"
 
-class G1CardTableEntryClosure;
-class G1RedirtyCardsQueue;
 class G1RedirtyCardsQueueSet;
 
 // Provide G1RedirtyCardsQueue with a thread-local qset.  It provides an
 // uncontended staging area for completed buffers, to be flushed to the
-// shared qset en masse.  Using the "base from member" idiom so the local
-// qset is constructed before being passed to the PtrQueue constructor.
-class G1RedirtyCardsQueueBase {
-  friend class G1RedirtyCardsQueue;
-  friend class G1RedirtyCardsQueueSet;
+// shared qset en masse.
+class G1RedirtyCardsLocalQueueSet : public PtrQueueSet {
+  G1RedirtyCardsQueueSet* _shared_qset;
+  G1BufferNodeList _buffers;
 
-  class LocalQSet : public PtrQueueSet {
-    G1RedirtyCardsQueueSet* _shared_qset;
-    G1BufferNodeList _buffers;
+public:
+  G1RedirtyCardsLocalQueueSet(G1RedirtyCardsQueueSet* shared_qset);
+  ~G1RedirtyCardsLocalQueueSet() NOT_DEBUG(= default);
 
-  public:
-    LocalQSet(G1RedirtyCardsQueueSet* shared_qset);
-    ~LocalQSet();
+  // Add the buffer to the local list.
+  virtual void enqueue_completed_buffer(BufferNode* node);
 
-    // Add the buffer to the local list.
-    virtual void enqueue_completed_buffer(BufferNode* node);
-
-    // Transfer all completed buffers to the shared qset.
-    void flush();
-
-    G1BufferNodeList take_all_completed_buffers();
-  };
-
-  G1RedirtyCardsQueueBase(G1RedirtyCardsQueueSet* shared_qset) :
-    _local_qset(shared_qset) {}
-
-  ~G1RedirtyCardsQueueBase() {}
-
-  LocalQSet _local_qset;
+  // Transfer all completed buffers to the shared qset.
+  void flush();
 };
 
 // Worker-local queues of card table entries.
-class G1RedirtyCardsQueue : private G1RedirtyCardsQueueBase, public PtrQueue {
+class G1RedirtyCardsQueue : public PtrQueue {
 protected:
   virtual void handle_completed_buffer();
 
 public:
-  G1RedirtyCardsQueue(G1RedirtyCardsQueueSet* qset);
-
-  // Flushes the queue.
-  ~G1RedirtyCardsQueue();
+  G1RedirtyCardsQueue(G1RedirtyCardsLocalQueueSet* qset);
+  ~G1RedirtyCardsQueue() NOT_DEBUG(= default);
 
   // Flushes all enqueued cards to qset.
   void flush();
@@ -97,8 +77,6 @@
   BufferNode* _tail;
   DEBUG_ONLY(mutable bool _collecting;)
 
-  typedef G1RedirtyCardsQueueBase::LocalQSet LocalQSet;
-
   void update_tail(BufferNode* node);
 
 public:
@@ -110,7 +88,7 @@
   // Collect buffers.  These functions are thread-safe.
   // precondition: Must not be concurrent with buffer processing.
   virtual void enqueue_completed_buffer(BufferNode* node);
-  void merge_bufferlist(LocalQSet* src);
+  void add_bufferlist(const G1BufferNodeList& buffers);
 
   // Processing phase operations.
   // precondition: Must not be concurrent with buffer collection.