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