• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/mem/gc/card_table-inl.h"
17 
18 #include "trace/trace.h"
19 #include "libpandabase/mem/mem.h"
20 #include "libpandabase/utils/logger.h"
21 
22 namespace ark::mem {
23 
24 using CardStatus = CardTable::Card::Status;
25 
CardTable(InternalAllocatorPtr internalAllocator,uintptr_t minAddress,size_t size)26 CardTable::CardTable(InternalAllocatorPtr internalAllocator, uintptr_t minAddress, size_t size)
27     : minAddress_(minAddress),
28       cardsCount_((size / CARD_SIZE) + (size % CARD_SIZE != 0 ? 1 : 0)),
29       internalAllocator_(internalAllocator)
30 {
31     /**
32      * We use this assumption in compiler's post barriers in case of store pair.
33      *
34      * The idea is to check whether two sequential slots of an object/array being
35      * written to belong to the same card or not.
36      *
37      * The only situation when they belong to different cards is when the second
38      * slot of the store is placed at the beggining of a card.
39      *
40      * This could be checked by `(2nd_store_ptr - min_address) % card_size == 0`
41      * condition, but if `min_address` is aligned at `card_size`, it may be simplified
42      * to `2nd_store_ptr % card_size == 0`.
43      */
44     ASSERT(IsAligned<GetCardSize()>(minAddress));
45 }
46 
~CardTable()47 CardTable::~CardTable()
48 {
49     ASSERT(cards_ != nullptr);
50     internalAllocator_->Free(cards_);
51 }
52 
Initialize()53 void CardTable::Initialize()
54 {
55     trace::ScopedTrace scopedTrace(__PRETTY_FUNCTION__);
56     if (cards_ != nullptr) {
57         LOG(FATAL, GC) << "try to initialize already initialized CardTable";
58     }
59     cards_ = static_cast<CardPtr>(internalAllocator_->Alloc(cardsCount_));
60     ClearCards(cards_, cardsCount_);
61     ASSERT(cards_ != nullptr);
62 }
63 
ClearCards(CardPtr start,size_t cardCount)64 void CardTable::ClearCards(CardPtr start, size_t cardCount)
65 {
66     static_assert(sizeof(Card) == sizeof(uint8_t));
67     [[maybe_unused]] auto err =
68         memset_s(reinterpret_cast<uint8_t *>(start), cardsCount_, Card::GetClearValue(), cardCount);
69     ASSERT(err == EOK);
70 }
71 
IsMarked(uintptr_t addr) const72 bool CardTable::IsMarked(uintptr_t addr) const
73 {
74     CardPtr card = GetCardPtr(addr);
75     return card->IsMarked();
76 }
77 
MarkCard(uintptr_t addr)78 void CardTable::MarkCard(uintptr_t addr)
79 {
80     CardPtr card = GetCardPtr(addr);
81     card->Mark();
82 }
83 
IsClear(uintptr_t addr) const84 bool CardTable::IsClear(uintptr_t addr) const
85 {
86     CardPtr card = GetCardPtr(addr);
87     return card->IsClear();
88 }
89 
ClearCard(uintptr_t addr)90 void CardTable::ClearCard(uintptr_t addr)
91 {
92     CardPtr card = GetCardPtr(addr);
93     card->Clear();
94 }
95 
ClearAll()96 void CardTable::ClearAll()
97 {
98     ClearCards(cards_, cardsCount_);
99 }
100 
ClearCardRange(uintptr_t beginAddr,uintptr_t endAddr)101 void CardTable::ClearCardRange(uintptr_t beginAddr, uintptr_t endAddr)
102 {
103     ASSERT((beginAddr - minAddress_) % CARD_SIZE == 0);
104     size_t cardsCount = (endAddr - beginAddr) / CARD_SIZE;
105     CardPtr start = GetCardPtr(beginAddr);
106     ClearCards(start, cardsCount);
107 }
108 
GetCardStartAddress(CardPtr card) const109 uintptr_t CardTable::GetCardStartAddress(CardPtr card) const
110 {
111     return minAddress_ + (ToUintPtr(card) - ToUintPtr(cards_)) * CARD_SIZE;
112 }
113 
GetCardEndAddress(CardPtr card) const114 uintptr_t CardTable::GetCardEndAddress(CardPtr card) const
115 {
116     return minAddress_ + (ToUintPtr(card + 1) - ToUintPtr(cards_)) * CARD_SIZE - 1;
117 }
118 
GetMemoryRange(CardPtr card) const119 MemRange CardTable::GetMemoryRange(CardPtr card) const
120 {
121     return MemRange(GetCardStartAddress(card), GetCardEndAddress(card));
122 }
123 
Card(uint8_t val)124 CardTable::Card::Card(uint8_t val)
125 {
126     SetCard(val);
127 }
128 
Mark()129 void CardTable::Card::Mark()
130 {
131     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
132     // on other reads or writes
133     value_.fetch_or(MARKED_VALUE, std::memory_order_relaxed);
134 }
135 
UnMark()136 void CardTable::Card::UnMark()
137 {
138     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
139     // on other reads or writes
140     value_.fetch_and(~MARKED_VALUE, std::memory_order_relaxed);
141 }
142 
Clear()143 void CardTable::Card::Clear()
144 {
145     SetCard(CLEAR_VALUE);
146 }
147 
SetProcessed()148 void CardTable::Card::SetProcessed()
149 {
150     SetCard(PROCESSED_VALUE);
151 }
152 
SetYoung()153 void CardTable::Card::SetYoung()
154 {
155     SetCard(YOUNG_VALUE);
156 }
157 
IsMarked() const158 bool CardTable::Card::IsMarked() const
159 {
160     return IsMarked(GetStatus());
161 }
162 
IsClear() const163 bool CardTable::Card::IsClear() const
164 {
165     return GetCard() == CLEAR_VALUE;
166 }
167 
IsProcessed() const168 bool CardTable::Card::IsProcessed() const
169 {
170     return IsProcessed(GetStatus());
171 }
172 
IsYoung() const173 bool CardTable::Card::IsYoung() const
174 {
175     return IsYoung(GetStatus());
176 }
177 
178 /* static */
IsMarked(CardStatus status)179 bool CardTable::Card::IsMarked(CardStatus status)
180 {
181     return status == MARKED_VALUE;
182 }
183 
184 /* static */
IsProcessed(CardStatus status)185 bool CardTable::Card::IsProcessed(CardStatus status)
186 {
187     return status == PROCESSED_VALUE;
188 }
189 
190 /* static */
IsYoung(CardStatus status)191 bool CardTable::Card::IsYoung(CardStatus status)
192 {
193     return status == YOUNG_VALUE;
194 }
195 
196 /* static */
GetStatus(uint8_t value)197 CardStatus CardTable::Card::GetStatus(uint8_t value)
198 {
199     return value & STATUS_MASK;
200 }
201 
IsHot() const202 bool CardTable::Card::IsHot() const
203 {
204     return IsHot(GetCard());
205 }
206 
SetHot()207 void CardTable::Card::SetHot()
208 {
209     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
210     // on other reads or writes
211     value_.fetch_or(HOT_FLAG, std::memory_order_relaxed);
212 }
213 
ResetHot()214 void CardTable::Card::ResetHot()
215 {
216     static constexpr auto RESET_HOT_MASK = uint8_t(~HOT_FLAG);
217     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
218     // on other reads or writes
219     value_.fetch_and(RESET_HOT_MASK, std::memory_order_relaxed);
220 }
221 
SetMaxHotValue()222 void CardTable::Card::SetMaxHotValue()
223 {
224     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
225     // on other reads or writes
226     value_.fetch_or(MAX_HOT_VALUE, std::memory_order_relaxed);
227 }
228 
IncrementHotValue()229 void CardTable::Card::IncrementHotValue()
230 {
231     ASSERT(!IsMaxHotValue(GetCard()));
232     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
233     // on other reads or writes
234     value_.fetch_add(HOT_VALUE, std::memory_order_relaxed);
235 }
236 
DecrementHotValue()237 void CardTable::Card::DecrementHotValue()
238 {
239     ASSERT(!IsMinHotValue(GetCard()));
240     // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
241     // on other reads or writes
242     value_.fetch_sub(HOT_VALUE, std::memory_order_relaxed);
243 }
244 
245 /* static */
IsMaxHotValue(uint8_t value)246 bool CardTable::Card::IsMaxHotValue(uint8_t value)
247 {
248     return (value & MAX_HOT_VALUE) == MAX_HOT_VALUE;
249 }
250 
251 /* static */
IsMinHotValue(uint8_t value)252 bool CardTable::Card::IsMinHotValue(uint8_t value)
253 {
254     return (value & MAX_HOT_VALUE) == 0;
255 }
256 
257 /* static */
IsHot(uint8_t value)258 bool CardTable::Card::IsHot(uint8_t value)
259 {
260     return (value & HOT_FLAG) == HOT_FLAG;
261 }
262 
GetCardPtr(uintptr_t addr) const263 CardTable::CardPtr CardTable::GetCardPtr(uintptr_t addr) const
264 {
265     ASSERT(addr >= minAddress_);
266     ASSERT(addr < minAddress_ + cardsCount_ * CARD_SIZE);
267     auto card = static_cast<CardPtr>(ToVoidPtr(ToUintPtr(cards_) + ((addr - minAddress_) >> LOG2_CARD_SIZE)));
268     return card;
269 }
270 
MarkCardsAsYoung(const MemRange & memRange)271 void CardTable::MarkCardsAsYoung(const MemRange &memRange)
272 {
273     CardPtrIterator curCard = CardPtrIterator(GetCardPtr(memRange.GetStartAddress()));
274     auto endCard = CardPtrIterator(GetCardPtr(memRange.GetEndAddress() - 1));
275     while (curCard != endCard) {
276         (*curCard)->SetYoung();
277         ++curCard;
278     }
279     (*curCard)->SetYoung();
280 }
281 }  // namespace ark::mem
282