1 /*
  2  * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "gc/g1/g1BarrierSet.inline.hpp"
 26 #include "gc/g1/g1CollectedHeap.inline.hpp"
 27 #include "gc/g1/g1HeapRegion.hpp"
 28 #include "gc/g1/g1SATBMarkQueueSet.hpp"
 29 #include "gc/g1/g1ThreadLocalData.hpp"
 30 #include "gc/shared/satbMarkQueue.hpp"
 31 #include "oops/oop.hpp"
 32 #include "utilities/debug.hpp"
 33 #include "utilities/globalDefinitions.hpp"
 34 
 35 G1SATBMarkQueueSet::G1SATBMarkQueueSet(BufferNode::Allocator* allocator) :
 36   SATBMarkQueueSet(allocator)
 37 {}
 38 
 39 void G1SATBMarkQueueSet::handle_zero_index_for_thread(Thread* t) {
 40   G1SATBMarkQueueSet& qset = G1BarrierSet::satb_mark_queue_set();
 41   qset.handle_zero_index(qset.satb_queue_for_thread(t));
 42 }
 43 
 44 SATBMarkQueue& G1SATBMarkQueueSet::satb_queue_for_thread(Thread* const t) const {
 45   return G1ThreadLocalData::satb_mark_queue(t);
 46 }
 47 
 48 // Return true if a SATB buffer entry refers to an object that
 49 // requires marking.
 50 //
 51 // The entry must point into the G1 heap.  In particular, it must not
 52 // be a null pointer.  null pointers are pre-filtered and never
 53 // inserted into a SATB buffer.
 54 //
 55 // An entry that is below the TAMS pointer for the containing heap
 56 // region requires marking. Such an entry must point to a valid object.
 57 //
 58 // An entry that is at least the TAMS pointer for the containing heap
 59 // region might be any of the following, none of which should be marked.
 60 //
 61 // * A reference to an object allocated since marking started.
 62 //   According to SATB, such objects are implicitly kept live and do
 63 //   not need to be dealt with via SATB buffer processing.
 64 //
 65 // * A reference to a young generation object. Young objects are
 66 //   handled separately and are not marked by concurrent marking.
 67 //
 68 // * A stale reference to a young generation object. If a young
 69 //   generation object reference is recorded and not filtered out
 70 //   before being moved by a young collection, the reference becomes
 71 //   stale.
 72 //
 73 // * A stale reference to an eagerly reclaimed humongous object.  If a
 74 //   humongous object is recorded and then reclaimed, the reference
 75 //   becomes stale.
 76 //
 77 // The stale reference cases are implicitly handled by the TAMS
 78 // comparison. Because of the possibility of stale references, buffer
 79 // processing must be somewhat circumspect and not assume entries
 80 // in an unfiltered buffer refer to valid objects.
 81 
 82 static inline bool requires_marking(const void* entry, G1CollectedHeap* g1h) {
 83   // Includes rejection of null pointers.
 84   assert(g1h->is_in_reserved(entry),
 85          "Non-heap pointer in SATB buffer: " PTR_FORMAT, p2i(entry));
 86 
 87   G1ConcurrentMark* cm = g1h->concurrent_mark();
 88   if (cm->obj_allocated_since_mark_start(cast_to_oop(entry))) {
 89     return false;
 90   }
 91 
 92   assert(oopDesc::is_oop(cast_to_oop(entry)),
 93          "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(entry));
 94 
 95   return true;
 96 }
 97 
 98 static inline bool discard_entry(const void* entry, G1CollectedHeap* g1h) {
 99   return !requires_marking(entry, g1h) || g1h->is_marked(cast_to_oop(entry));
100 }
101 
102 // Workaround for not yet having std::bind.
103 class G1SATBMarkQueueFilterFn {
104   G1CollectedHeap* _g1h;
105 
106 public:
107   G1SATBMarkQueueFilterFn() : _g1h(G1CollectedHeap::heap()) {}
108 
109   // Return true if entry should be filtered out (removed), false if
110   // it should be retained.
111   bool operator()(const void* entry) const {
112     return discard_entry(entry, _g1h);
113   }
114 };
115 
116 void G1SATBMarkQueueSet::filter(SATBMarkQueue& queue) {
117   apply_filter(G1SATBMarkQueueFilterFn(), queue);
118 }