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 }