xref: /aosp_15_r20/art/runtime/gc/accounting/bitmap-inl.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_GC_ACCOUNTING_BITMAP_INL_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_GC_ACCOUNTING_BITMAP_INL_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "bitmap.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include <memory>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker #include "base/atomic.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker namespace gc {
31*795d594fSAndroid Build Coastguard Worker namespace accounting {
32*795d594fSAndroid Build Coastguard Worker 
AtomicTestAndSetBit(uintptr_t bit_index)33*795d594fSAndroid Build Coastguard Worker inline bool Bitmap::AtomicTestAndSetBit(uintptr_t bit_index) {
34*795d594fSAndroid Build Coastguard Worker   CheckValidBitIndex(bit_index);
35*795d594fSAndroid Build Coastguard Worker   const size_t word_index = BitIndexToWordIndex(bit_index);
36*795d594fSAndroid Build Coastguard Worker   const uintptr_t word_mask = BitIndexToMask(bit_index);
37*795d594fSAndroid Build Coastguard Worker   auto* atomic_entry = reinterpret_cast<Atomic<uintptr_t>*>(&bitmap_begin_[word_index]);
38*795d594fSAndroid Build Coastguard Worker   uintptr_t old_word;
39*795d594fSAndroid Build Coastguard Worker   do {
40*795d594fSAndroid Build Coastguard Worker     old_word = atomic_entry->load(std::memory_order_relaxed);
41*795d594fSAndroid Build Coastguard Worker     // Fast path: The bit is already set.
42*795d594fSAndroid Build Coastguard Worker     if ((old_word & word_mask) != 0) {
43*795d594fSAndroid Build Coastguard Worker       DCHECK(TestBit(bit_index));
44*795d594fSAndroid Build Coastguard Worker       return true;
45*795d594fSAndroid Build Coastguard Worker     }
46*795d594fSAndroid Build Coastguard Worker   } while (!atomic_entry->CompareAndSetWeakSequentiallyConsistent(old_word, old_word | word_mask));
47*795d594fSAndroid Build Coastguard Worker   DCHECK(TestBit(bit_index));
48*795d594fSAndroid Build Coastguard Worker   return false;
49*795d594fSAndroid Build Coastguard Worker }
50*795d594fSAndroid Build Coastguard Worker 
TestBit(uintptr_t bit_index)51*795d594fSAndroid Build Coastguard Worker inline bool Bitmap::TestBit(uintptr_t bit_index) const {
52*795d594fSAndroid Build Coastguard Worker   CheckValidBitIndex(bit_index);
53*795d594fSAndroid Build Coastguard Worker   return (bitmap_begin_[BitIndexToWordIndex(bit_index)] & BitIndexToMask(bit_index)) != 0;
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker template<typename Visitor>
VisitSetBits(uintptr_t bit_start,uintptr_t bit_end,const Visitor & visitor)57*795d594fSAndroid Build Coastguard Worker inline void Bitmap::VisitSetBits(uintptr_t bit_start, uintptr_t bit_end, const Visitor& visitor)
58*795d594fSAndroid Build Coastguard Worker     const {
59*795d594fSAndroid Build Coastguard Worker   DCHECK_LE(bit_start, bit_end);
60*795d594fSAndroid Build Coastguard Worker   CheckValidBitIndex(bit_start);
61*795d594fSAndroid Build Coastguard Worker   const uintptr_t index_start = BitIndexToWordIndex(bit_start);
62*795d594fSAndroid Build Coastguard Worker   const uintptr_t index_end = BitIndexToWordIndex(bit_end);
63*795d594fSAndroid Build Coastguard Worker   if (bit_start != bit_end) {
64*795d594fSAndroid Build Coastguard Worker     CheckValidBitIndex(bit_end - 1);
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker 
67*795d594fSAndroid Build Coastguard Worker   // Index(begin)  ...    Index(end)
68*795d594fSAndroid Build Coastguard Worker   // [xxxxx???][........][????yyyy]
69*795d594fSAndroid Build Coastguard Worker   //      ^                   ^
70*795d594fSAndroid Build Coastguard Worker   //      |                   #---- Bit of visit_end
71*795d594fSAndroid Build Coastguard Worker   //      #---- Bit of visit_begin
72*795d594fSAndroid Build Coastguard Worker   //
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker   // Left edge.
75*795d594fSAndroid Build Coastguard Worker   uintptr_t left_edge = bitmap_begin_[index_start];
76*795d594fSAndroid Build Coastguard Worker   // Clear the lower bits that are not in range.
77*795d594fSAndroid Build Coastguard Worker   left_edge &= ~((static_cast<uintptr_t>(1) << (bit_start % kBitsPerBitmapWord)) - 1);
78*795d594fSAndroid Build Coastguard Worker 
79*795d594fSAndroid Build Coastguard Worker   // Right edge. Either unique, or left_edge.
80*795d594fSAndroid Build Coastguard Worker   uintptr_t right_edge;
81*795d594fSAndroid Build Coastguard Worker 
82*795d594fSAndroid Build Coastguard Worker   if (index_start < index_end) {
83*795d594fSAndroid Build Coastguard Worker     // Left edge != right edge.
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker     // Traverse left edge.
86*795d594fSAndroid Build Coastguard Worker     if (left_edge != 0) {
87*795d594fSAndroid Build Coastguard Worker       const uintptr_t ptr_base = WordIndexToBitIndex(index_start);
88*795d594fSAndroid Build Coastguard Worker       do {
89*795d594fSAndroid Build Coastguard Worker         const size_t shift = CTZ(left_edge);
90*795d594fSAndroid Build Coastguard Worker         visitor(ptr_base + shift);
91*795d594fSAndroid Build Coastguard Worker         left_edge ^= static_cast<uintptr_t>(1) << shift;
92*795d594fSAndroid Build Coastguard Worker       } while (left_edge != 0);
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker     // Traverse the middle, full part.
96*795d594fSAndroid Build Coastguard Worker     for (size_t i = index_start + 1; i < index_end; ++i) {
97*795d594fSAndroid Build Coastguard Worker       uintptr_t w = bitmap_begin_[i];
98*795d594fSAndroid Build Coastguard Worker       if (w != 0) {
99*795d594fSAndroid Build Coastguard Worker         const uintptr_t ptr_base = WordIndexToBitIndex(i);
100*795d594fSAndroid Build Coastguard Worker         do {
101*795d594fSAndroid Build Coastguard Worker           const size_t shift = CTZ(w);
102*795d594fSAndroid Build Coastguard Worker           visitor(ptr_base + shift);
103*795d594fSAndroid Build Coastguard Worker           w ^= static_cast<uintptr_t>(1) << shift;
104*795d594fSAndroid Build Coastguard Worker         } while (w != 0);
105*795d594fSAndroid Build Coastguard Worker       }
106*795d594fSAndroid Build Coastguard Worker     }
107*795d594fSAndroid Build Coastguard Worker 
108*795d594fSAndroid Build Coastguard Worker     // Right edge is unique.
109*795d594fSAndroid Build Coastguard Worker     // But maybe we don't have anything to do: visit_end starts in a new word...
110*795d594fSAndroid Build Coastguard Worker     if (bit_end == 0) {
111*795d594fSAndroid Build Coastguard Worker       // Do not read memory, as it could be after the end of the bitmap.
112*795d594fSAndroid Build Coastguard Worker       right_edge = 0;
113*795d594fSAndroid Build Coastguard Worker     } else {
114*795d594fSAndroid Build Coastguard Worker       right_edge = bitmap_begin_[index_end];
115*795d594fSAndroid Build Coastguard Worker     }
116*795d594fSAndroid Build Coastguard Worker   } else {
117*795d594fSAndroid Build Coastguard Worker     right_edge = left_edge;
118*795d594fSAndroid Build Coastguard Worker   }
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker   // Right edge handling.
121*795d594fSAndroid Build Coastguard Worker   right_edge &= ((static_cast<uintptr_t>(1) << (bit_end % kBitsPerBitmapWord)) - 1);
122*795d594fSAndroid Build Coastguard Worker   if (right_edge != 0) {
123*795d594fSAndroid Build Coastguard Worker     const uintptr_t ptr_base = WordIndexToBitIndex(index_end);
124*795d594fSAndroid Build Coastguard Worker     do {
125*795d594fSAndroid Build Coastguard Worker       const size_t shift = CTZ(right_edge);
126*795d594fSAndroid Build Coastguard Worker       visitor(ptr_base + shift);
127*795d594fSAndroid Build Coastguard Worker       right_edge ^= (static_cast<uintptr_t>(1)) << shift;
128*795d594fSAndroid Build Coastguard Worker     } while (right_edge != 0);
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker template<bool kSetBit>
ModifyBit(uintptr_t bit_index)133*795d594fSAndroid Build Coastguard Worker inline bool Bitmap::ModifyBit(uintptr_t bit_index) {
134*795d594fSAndroid Build Coastguard Worker   CheckValidBitIndex(bit_index);
135*795d594fSAndroid Build Coastguard Worker   const size_t word_index = BitIndexToWordIndex(bit_index);
136*795d594fSAndroid Build Coastguard Worker   const uintptr_t word_mask = BitIndexToMask(bit_index);
137*795d594fSAndroid Build Coastguard Worker   uintptr_t* address = &bitmap_begin_[word_index];
138*795d594fSAndroid Build Coastguard Worker   uintptr_t old_word = *address;
139*795d594fSAndroid Build Coastguard Worker   if (kSetBit) {
140*795d594fSAndroid Build Coastguard Worker     *address = old_word | word_mask;
141*795d594fSAndroid Build Coastguard Worker   } else {
142*795d594fSAndroid Build Coastguard Worker     *address = old_word & ~word_mask;
143*795d594fSAndroid Build Coastguard Worker   }
144*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(TestBit(bit_index), kSetBit);
145*795d594fSAndroid Build Coastguard Worker   return (old_word & word_mask) != 0;
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker }  // namespace accounting
149*795d594fSAndroid Build Coastguard Worker }  // namespace gc
150*795d594fSAndroid Build Coastguard Worker }  // namespace art
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_GC_ACCOUNTING_BITMAP_INL_H_
153