1 /*
2 * Copyright (c) 2015, 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 #ifndef SHARE_GC_Z_ZLIVEMAP_INLINE_HPP
25 #define SHARE_GC_Z_ZLIVEMAP_INLINE_HPP
26
27 #include "gc/z/zLiveMap.hpp"
28
29 #include "gc/z/zAddress.inline.hpp"
30 #include "gc/z/zBitMap.inline.hpp"
31 #include "gc/z/zGeneration.inline.hpp"
32 #include "gc/z/zMark.hpp"
33 #include "gc/z/zUtils.inline.hpp"
34 #include "utilities/bitMap.inline.hpp"
35 #include "utilities/debug.hpp"
36
37 inline void ZLiveMap::reset() {
38 _seqnum.store_relaxed(0u);
39 }
40
41 inline bool ZLiveMap::is_marked(ZGenerationId id) const {
42 return _seqnum.load_acquire() == ZGeneration::generation(id)->seqnum();
43 }
44
45 inline uint32_t ZLiveMap::live_objects() const {
46 return _live_objects.load_relaxed();
47 }
48
49 inline size_t ZLiveMap::live_bytes() const {
50 return _live_bytes.load_relaxed();
51 }
52
53 inline const BitMapView ZLiveMap::segment_live_bits() const {
54 return BitMapView(const_cast<BitMap::bm_word_t*>(&_segment_live_bits), NumSegments);
55 }
56
57 inline const BitMapView ZLiveMap::segment_claim_bits() const {
58 return BitMapView(const_cast<BitMap::bm_word_t*>(&_segment_claim_bits), NumSegments);
59 }
60
61 inline BitMapView ZLiveMap::segment_live_bits() {
62 return BitMapView(&_segment_live_bits, NumSegments);
63 }
64
65 inline BitMapView ZLiveMap::segment_claim_bits() {
66 return BitMapView(&_segment_claim_bits, NumSegments);
67 }
68
69 inline bool ZLiveMap::is_segment_live(BitMap::idx_t segment) const {
70 return segment_live_bits().par_at(segment);
71 }
72
73 inline bool ZLiveMap::set_segment_live(BitMap::idx_t segment) {
74 return segment_live_bits().par_set_bit(segment, memory_order_release);
75 }
76
77 inline bool ZLiveMap::claim_segment(BitMap::idx_t segment) {
78 return segment_claim_bits().par_set_bit(segment, memory_order_acq_rel);
79 }
80
81 inline BitMap::idx_t ZLiveMap::first_live_segment() const {
82 return segment_live_bits().find_first_set_bit(0, NumSegments);
83 }
84
85 inline BitMap::idx_t ZLiveMap::next_live_segment(BitMap::idx_t segment) const {
86 return segment_live_bits().find_first_set_bit(segment + 1, NumSegments);
87 }
88
89 inline BitMap::idx_t ZLiveMap::index_to_segment(BitMap::idx_t index) const {
90 return index >> _segment_shift;
91 }
92
93 inline bool ZLiveMap::get(ZGenerationId id, BitMap::idx_t index) const {
94 const BitMap::idx_t segment = index_to_segment(index);
95 return is_marked(id) && // Page is marked
96 is_segment_live(segment) && // Segment is marked
97 _bitmap.par_at(index, memory_order_relaxed); // Object is marked
98 }
99
100 inline bool ZLiveMap::set(ZGenerationId id, BitMap::idx_t index, bool finalizable, bool& inc_live) {
101 if (!is_marked(id)) {
102 // First object to be marked during this
103 // cycle, reset marking information.
104 reset(id);
105 }
106
107 const BitMap::idx_t segment = index_to_segment(index);
108 if (!is_segment_live(segment)) {
109 // First object to be marked in this segment during
110 // this cycle, reset segment bitmap.
111 reset_segment(segment);
112 }
113
114 return _bitmap.par_set_bit_pair(index, finalizable, inc_live);
115 }
116
117 inline void ZLiveMap::inc_live(uint32_t objects, size_t bytes) {
118 _live_objects.add_then_fetch(objects);
119 _live_bytes.add_then_fetch(bytes);
120 }
121
122 inline BitMap::idx_t ZLiveMap::segment_start(BitMap::idx_t segment) const {
123 return segment * _segment_size;
124 }
125
126 inline BitMap::idx_t ZLiveMap::segment_end(BitMap::idx_t segment) const {
127 return segment_start(segment) + _segment_size;
128 }
129
130 inline size_t ZLiveMap::do_object(ObjectClosure* cl, zaddress addr) const {
131 // Get the size of the object before calling the closure, which
132 // might overwrite the object in case we are relocating in-place.
133 const size_t size = ZUtils::object_size(addr);
134
135 // Apply closure
136 cl->do_object(to_oop(addr));
137
138 return size;
139 }
140
141 template <typename Function>
142 inline void ZLiveMap::iterate_segment(BitMap::idx_t segment, Function function) {
143 assert(is_segment_live(segment), "Must be");
144
145 const BitMap::idx_t start_index = segment_start(segment);
146 const BitMap::idx_t end_index = segment_end(segment);
147
148 _bitmap.iterate(function, start_index, end_index);
149 }
150
151 template <typename Function>
152 inline void ZLiveMap::iterate(ZGenerationId id, Function function) {
153 if (!is_marked(id)) {
154 return;
155 }
156
157 auto live_only = [&](BitMap::idx_t index) -> bool {
158 if ((index & 1) == 0) {
159 return function(index);
160 }
161 // Don't visit the finalizable bits
162 return true;
163 };
164
165 for (BitMap::idx_t segment = first_live_segment(); segment < NumSegments; segment = next_live_segment(segment)) {
166 // For each live segment
167 iterate_segment(segment, live_only);
168 }
169 }
170
171 // Find the bit index that correspond the start of the object that is lower,
172 // or equal, to the given index (index is inclusive).
173 //
174 // Typically used to find the start of an object when there's only a field
175 // address available. Note that it's not guaranteed that the found index
176 // corresponds to an object that spans the given index. This function just
177 // looks at the bits. The calling code is responsible to check the object
178 // at the returned index.
179 //
180 // returns -1 if no bit was found
181 inline BitMap::idx_t ZLiveMap::find_base_bit(BitMap::idx_t index) {
182 // Check first segment
183 const BitMap::idx_t start_segment = index_to_segment(index);
184 if (is_segment_live(start_segment)) {
185 const BitMap::idx_t res = find_base_bit_in_segment(segment_start(start_segment), index);
186 if (res != BitMap::idx_t(-1)) {
187 return res;
188 }
189 }
190
191 // Search earlier segments
192 for (BitMap::idx_t segment = start_segment; segment-- > 0; ) {
193 if (is_segment_live(segment)) {
194 const BitMap::idx_t res = find_base_bit_in_segment(segment_start(segment), segment_end(segment) - 1);
195 if (res != BitMap::idx_t(-1)) {
196 return res;
197 }
198 }
199 }
200
201 // Not found
202 return BitMap::idx_t(-1);
203 }
204
205 // Find the bit index that correspond the start of the object that is lower,
206 // or equal, to the given index (index is inclusive). Stopping when reaching
207 // start.
208 inline BitMap::idx_t ZLiveMap::find_base_bit_in_segment(BitMap::idx_t start, BitMap::idx_t index) {
209 assert(index_to_segment(start) == index_to_segment(index), "Only supports searches within segments start: %zu index: %zu", start, index);
210 assert(is_segment_live(index_to_segment(start)), "Must be live");
211
212 // Search backwards - + 1 to make an exclusive index.
213 const BitMap::idx_t end = index + 1;
214 const BitMap::idx_t bit = _bitmap.find_last_set_bit(start, end);
215 if (bit == end) {
216 return BitMap::idx_t(-1);
217 }
218
219 // The bitmaps contain pairs of bits to deal with strongly marked vs only
220 // finalizable marked. Align down to get the first bit position.
221 return bit & ~BitMap::idx_t(1);
222 }
223
224 #endif // SHARE_GC_Z_ZLIVEMAP_INLINE_HPP