1 /**
2 * Copyright (c) 2021-2022 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 panda::mem {
23
CardTable(InternalAllocatorPtr internalAllocator,uintptr_t minAddress,size_t size)24 CardTable::CardTable(InternalAllocatorPtr internalAllocator, uintptr_t minAddress, size_t size)
25 : minAddress_(minAddress),
26 cardsCount_((size / CARD_SIZE) + (size % CARD_SIZE != 0 ? 1 : 0)),
27 internalAllocator_(internalAllocator)
28 {
29 /**
30 * We use this assumption in compiler's post barriers in case of store pair.
31 *
32 * The idea is to check whether two sequential slots of an object/array being
33 * written to belong to the same card or not.
34 *
35 * The only situation when they belong to different cards is when the second
36 * slot of the store is placed at the beggining of a card.
37 *
38 * This could be checked by `(2nd_store_ptr - min_address) % card_size == 0`
39 * condition, but if `min_address` is aligned at `card_size`, it may be simplified
40 * to `2nd_store_ptr % card_size == 0`.
41 */
42 ASSERT(IsAligned<GetCardSize()>(minAddress));
43 }
44
~CardTable()45 CardTable::~CardTable()
46 {
47 ASSERT(cards_ != nullptr);
48 internalAllocator_->Free(cards_);
49 }
50
Initialize()51 void CardTable::Initialize()
52 {
53 trace::ScopedTrace scopedTrace(__PRETTY_FUNCTION__);
54 if (cards_ != nullptr) {
55 LOG(FATAL, GC) << "try to initialize already initialized CardTable";
56 }
57 cards_ = static_cast<CardPtr>(internalAllocator_->Alloc(cardsCount_));
58 ClearCards(cards_, cardsCount_);
59 ASSERT(cards_ != nullptr);
60 }
61
ClearCards(CardPtr start,size_t cardCount)62 void CardTable::ClearCards(CardPtr start, size_t cardCount)
63 {
64 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
65 CardPtr end = start + cardCount;
66 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
67 for (auto *curCard = start; curCard < end; ++curCard) {
68 curCard->Clear();
69 }
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
IsMarked() const129 bool CardTable::Card::IsMarked() const
130 {
131 return GetCard() == MARKED_VALUE;
132 }
133
Mark()134 void CardTable::Card::Mark()
135 {
136 SetCard(MARKED_VALUE);
137 }
138
IsClear() const139 bool CardTable::Card::IsClear() const
140 {
141 return GetCard() == CLEAR_VALUE;
142 }
143
Clear()144 void CardTable::Card::Clear()
145 {
146 SetCard(CLEAR_VALUE);
147 }
148
IsProcessed() const149 bool CardTable::Card::IsProcessed() const
150 {
151 return GetCard() == PROCESSED_VALUE;
152 }
153
SetProcessed()154 void CardTable::Card::SetProcessed()
155 {
156 SetCard(PROCESSED_VALUE);
157 }
158
IsYoung() const159 bool CardTable::Card::IsYoung() const
160 {
161 return GetCard() == YOUNG_VALUE;
162 }
163
SetYoung()164 void CardTable::Card::SetYoung()
165 {
166 SetCard(YOUNG_VALUE);
167 }
168
GetCardPtr(uintptr_t addr) const169 CardTable::CardPtr CardTable::GetCardPtr(uintptr_t addr) const
170 {
171 ASSERT(addr >= minAddress_);
172 ASSERT(addr < minAddress_ + cardsCount_ * CARD_SIZE);
173 auto card = static_cast<CardPtr>(ToVoidPtr(ToUintPtr(cards_) + ((addr - minAddress_) >> LOG2_CARD_SIZE)));
174 return card;
175 }
176
MarkCardsAsYoung(const MemRange & memRange)177 void CardTable::MarkCardsAsYoung(const MemRange &memRange)
178 {
179 CardPtrIterator curCard = CardPtrIterator(GetCardPtr(memRange.GetStartAddress()));
180 auto endCard = CardPtrIterator(GetCardPtr(memRange.GetEndAddress() - 1));
181 while (curCard != endCard) {
182 (*curCard)->SetYoung();
183 ++curCard;
184 }
185 (*curCard)->SetYoung();
186 }
187 } // namespace panda::mem
188