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.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 internal_allocator,uintptr_t min_address,size_t size)24 CardTable::CardTable(InternalAllocatorPtr internal_allocator, uintptr_t min_address, size_t size)
25 : min_address_(min_address),
26 cards_count_((size / CARD_SIZE) + (size % CARD_SIZE != 0 ? 1 : 0)),
27 internal_allocator_(internal_allocator)
28 {
29 }
30
~CardTable()31 CardTable::~CardTable()
32 {
33 ASSERT(cards_ != nullptr);
34 internal_allocator_->Free(cards_);
35 }
36
Initialize()37 void CardTable::Initialize()
38 {
39 trace::ScopedTrace scoped_trace(__PRETTY_FUNCTION__);
40 if (cards_ != nullptr) {
41 LOG(FATAL, GC) << "try to initialize already initialized CardTable";
42 }
43 cards_ = static_cast<CardPtr>(internal_allocator_->Alloc(cards_count_));
44 ClearCards(cards_, cards_count_);
45 ASSERT(cards_ != nullptr);
46 }
47
ClearCards(CardPtr start,size_t card_count)48 void CardTable::ClearCards(CardPtr start, size_t card_count)
49 {
50 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
51 CardPtr end = start + card_count;
52 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
53 for (auto *cur_card = start; cur_card < end; ++cur_card) {
54 cur_card->Clear();
55 }
56 }
57
IsMarked(uintptr_t addr) const58 bool CardTable::IsMarked(uintptr_t addr) const
59 {
60 CardPtr card = GetCardPtr(addr);
61 return card->IsMarked();
62 }
63
MarkCard(uintptr_t addr)64 void CardTable::MarkCard(uintptr_t addr)
65 {
66 CardPtr card = GetCardPtr(addr);
67 card->Mark();
68 }
69
IsClear(uintptr_t addr) const70 bool CardTable::IsClear(uintptr_t addr) const
71 {
72 CardPtr card = GetCardPtr(addr);
73 return card->IsClear();
74 }
75
ClearCard(uintptr_t addr)76 void CardTable::ClearCard(uintptr_t addr)
77 {
78 CardPtr card = GetCardPtr(addr);
79 card->Clear();
80 }
81
ClearAll()82 void CardTable::ClearAll()
83 {
84 ClearCards(cards_, cards_count_);
85 }
86
ClearCardRange(uintptr_t begin_addr,uintptr_t end_addr)87 void CardTable::ClearCardRange(uintptr_t begin_addr, uintptr_t end_addr)
88 {
89 ASSERT((begin_addr - min_address_) % CARD_SIZE == 0);
90 size_t cards_count = (end_addr - begin_addr) / CARD_SIZE;
91 CardPtr start = GetCardPtr(begin_addr);
92 ClearCards(start, cards_count);
93 }
94
GetCardStartAddress(CardPtr card) const95 uintptr_t CardTable::GetCardStartAddress(CardPtr card) const
96 {
97 return min_address_ + (ToUintPtr(card) - ToUintPtr(cards_)) * CARD_SIZE;
98 }
99
GetCardEndAddress(CardPtr card) const100 uintptr_t CardTable::GetCardEndAddress(CardPtr card) const
101 {
102 return min_address_ + (ToUintPtr(card + 1) - ToUintPtr(cards_)) * CARD_SIZE - 1;
103 }
104
GetMemoryRange(CardPtr card) const105 MemRange CardTable::GetMemoryRange(CardPtr card) const
106 {
107 return MemRange(GetCardStartAddress(card), GetCardEndAddress(card));
108 }
109
Card(uint8_t val)110 CardTable::Card::Card(uint8_t val)
111 {
112 SetCard(val);
113 }
114
IsMarked() const115 bool CardTable::Card::IsMarked() const
116 {
117 return GetCard() == MARKED_VALUE;
118 }
119
Mark()120 void CardTable::Card::Mark()
121 {
122 SetCard(MARKED_VALUE);
123 }
124
IsClear() const125 bool CardTable::Card::IsClear() const
126 {
127 return GetCard() == CLEAR_VALUE;
128 }
129
Clear()130 void CardTable::Card::Clear()
131 {
132 SetCard(CLEAR_VALUE);
133 }
134
IsProcessed() const135 bool CardTable::Card::IsProcessed() const
136 {
137 return GetCard() == PROCESSED_VALUE;
138 }
139
SetProcessed()140 void CardTable::Card::SetProcessed()
141 {
142 SetCard(PROCESSED_VALUE);
143 }
144
IsYoung() const145 bool CardTable::Card::IsYoung() const
146 {
147 return GetCard() == YOUNG_VALUE;
148 }
149
SetYoung()150 void CardTable::Card::SetYoung()
151 {
152 SetCard(YOUNG_VALUE);
153 }
154
GetCard() const155 uint8_t CardTable::Card::GetCard() const
156 {
157 // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
158 // on other reads or writes
159 return value_.load(std::memory_order_relaxed);
160 }
161
SetCard(uint8_t new_val)162 void CardTable::Card::SetCard(uint8_t new_val)
163 {
164 // Atomic with relaxed order reason: data race with value_ with no synchronization or ordering constraints imposed
165 // on other reads or writes
166 value_.store(new_val, std::memory_order_relaxed);
167 }
168
GetCardPtr(uintptr_t addr) const169 CardTable::CardPtr CardTable::GetCardPtr(uintptr_t addr) const
170 {
171 ASSERT(addr >= min_address_);
172 ASSERT(addr < min_address_ + cards_count_ * CARD_SIZE);
173 auto card = static_cast<CardPtr>(ToVoidPtr(ToUintPtr(cards_) + ((addr - min_address_) >> LOG2_CARD_SIZE)));
174 return card;
175 }
176
MarkCardsAsYoung(const MemRange & mem_range)177 void CardTable::MarkCardsAsYoung(const MemRange &mem_range)
178 {
179 CardPtrIterator cur_card = CardPtrIterator(GetCardPtr(mem_range.GetStartAddress()));
180 auto end_card = CardPtrIterator(GetCardPtr(mem_range.GetEndAddress() - 1));
181 while (cur_card != end_card) {
182 (*cur_card)->SetYoung();
183 ++cur_card;
184 }
185 (*cur_card)->SetYoung();
186 }
187 } // namespace panda::mem
188