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 #ifndef PANDA_MEM_GC_G1_REM_SET_INL_H
17 #define PANDA_MEM_GC_G1_REM_SET_INL_H
18
19 #include "runtime/mem/rem_set.h"
20 #include "runtime/mem/region_space-inl.h"
21 #include "runtime/mem/region_allocator.h"
22
23 namespace panda::mem {
24
25 template <typename LockConfigT>
RemSet(Region * region,CardTable * card_table)26 RemSet<LockConfigT>::RemSet(Region *region, CardTable *card_table)
27 : region_(region), allocator_(region->GetInternalAllocator()), card_table_(card_table)
28 {
29 }
30
31 template <typename LockConfigT>
~RemSet()32 RemSet<LockConfigT>::~RemSet()
33 {
34 Clear();
35 }
36
37 template <typename LockConfigT>
38 template <bool need_lock>
AddRef(const ObjectHeader * from_obj_addr)39 void RemSet<LockConfigT>::AddRef(const ObjectHeader *from_obj_addr)
40 {
41 ASSERT(from_obj_addr != nullptr);
42 auto from_region = ObjectToRegion(from_obj_addr);
43 ASSERT(from_region != nullptr);
44 auto card_ptr = GetCardPtr(from_obj_addr);
45 auto list = GetCardList<need_lock>(from_region);
46 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
47 if (list == nullptr) {
48 list = allocator_->New<CardList>();
49 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
50 regions_[from_region] = list;
51 }
52 if (find(list->begin(), list->end(), card_ptr) == list->end()) {
53 list->push_back(card_ptr);
54 }
55 }
56
57 template <typename LockConfigT>
Clear()58 void RemSet<LockConfigT>::Clear()
59 {
60 os::memory::LockHolder lock(rem_set_lock_);
61 for (auto region_iter : regions_) {
62 auto list = region_iter.second;
63 allocator_->Delete(list);
64 }
65 regions_.clear();
66 ref_regions_.clear();
67 }
68
69 template <typename LockConfigT>
70 template <bool need_lock>
GetCardList(Region * region)71 CardList *RemSet<LockConfigT>::GetCardList(Region *region)
72 {
73 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
74 auto card_list = regions_.find(region);
75 if (card_list == regions_.end()) {
76 return nullptr;
77 }
78 return card_list->second;
79 }
80
81 template <typename LockConfigT>
GetCardPtr(const void * addr)82 CardPtr RemSet<LockConfigT>::GetCardPtr(const void *addr)
83 {
84 return card_table_ != nullptr ? card_table_->GetCardPtr(ToUintPtr(addr)) : nullptr;
85 }
86
87 template <typename LockConfigT>
GetMemoryRange(CardPtr card)88 MemRange RemSet<LockConfigT>::GetMemoryRange(CardPtr card)
89 {
90 return card_table_->GetMemoryRange(card);
91 }
92
93 /* static */
94 template <typename LockConfigT>
95 template <bool need_lock>
InvalidateRegion(Region * invalid_region)96 void RemSet<LockConfigT>::InvalidateRegion(Region *invalid_region)
97 {
98 RemSet<> *invalid_remset = invalid_region->GetRemSet();
99 os::memory::LockHolder<LockConfigT, need_lock> lock(invalid_remset->rem_set_lock_);
100 for (Region *ref_reg : invalid_remset->ref_regions_) {
101 ref_reg->GetRemSet()->RemoveFromRegion<need_lock>(invalid_region);
102 }
103
104 for (auto entry : invalid_remset->regions_) {
105 Region *from_region = entry.first;
106 from_region->GetRemSet()->RemoveRefRegion<need_lock>(invalid_region);
107 }
108 }
109
110 /* static */
111 template <typename LockConfigT>
112 template <bool need_lock>
AddRefWithAddr(const ObjectHeader * obj_addr,const ObjectHeader * value_addr)113 void RemSet<LockConfigT>::AddRefWithAddr(const ObjectHeader *obj_addr, const ObjectHeader *value_addr)
114 {
115 auto *from_region = ObjectToRegion(obj_addr);
116 auto *to_region = ObjectToRegion(value_addr);
117 // TSAN thinks that we can have a data race here when we get region or getRemSet from region, because we don't have
118 // synchronization between these events. In reality it's impossible, because if we get write from/to region it
119 // should be created already by allocator in mutator thread, and only then writes happens.
120 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN();
121 ASSERT(from_region != nullptr);
122 ASSERT(from_region->GetRemSet() != nullptr);
123 ASSERT(to_region != nullptr);
124 ASSERT(to_region->GetRemSet() != nullptr);
125
126 to_region->GetRemSet()->AddRef<need_lock>(obj_addr);
127 from_region->GetRemSet()->AddRefRegion<need_lock>(to_region);
128 TSAN_ANNOTATE_IGNORE_WRITES_END();
129 }
130
131 /* static */
132 template <typename LockConfigT>
TraverseObjectToAddRef(const void * addr)133 void RemSet<LockConfigT>::TraverseObjectToAddRef(const void *addr)
134 {
135 // TODO(xucheng) : need a special thread to add ref.
136 auto traverse_object_visitor = [](ObjectHeader *from_object, ObjectHeader *object_to_traverse) {
137 AddRefWithAddr(from_object, object_to_traverse);
138 };
139 auto obj = static_cast<ObjectHeader *>(const_cast<void *>(addr));
140 GCStaticObjectHelpers::TraverseAllObjects(obj, traverse_object_visitor);
141 }
142
143 template <typename LockConfigT>
144 template <bool need_lock, typename ObjectVisitor>
VisitMarkedCards(const ObjectVisitor & object_visitor)145 inline void RemSet<LockConfigT>::VisitMarkedCards(const ObjectVisitor &object_visitor)
146 {
147 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
148 auto visitor = [&object_visitor](void *mem) { object_visitor(static_cast<ObjectHeader *>(mem)); };
149 for (auto region_iter : regions_) {
150 auto *region = region_iter.first;
151 auto *card_list = region_iter.second;
152 if (region == nullptr) {
153 // process humongous
154 continue;
155 } else { // NOLINT(readability-else-after-return)
156 for (auto card_ptr : *card_list) {
157 // visit live objects in old region
158 auto mem_range = GetMemoryRange(card_ptr);
159 region->GetLiveBitmap()->IterateOverMarkedChunkInRange(ToVoidPtr(mem_range.GetStartAddress()),
160 ToVoidPtr(mem_range.GetEndAddress()), visitor);
161 }
162 }
163 }
164 }
165
166 template <typename LockConfigT>
167 template <bool need_lock, typename CardVisitor>
ProceedMarkedCards(const CardVisitor & card_visitor)168 inline void RemSet<LockConfigT>::ProceedMarkedCards(const CardVisitor &card_visitor)
169 {
170 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
171 for (auto region_iter : regions_) {
172 auto *region = region_iter.first;
173 auto *card_list = region_iter.second;
174 if (region == nullptr) {
175 // process humongous
176 continue;
177 } else { // NOLINT(readability-else-after-return)
178 for (auto card_ptr : *card_list) {
179 // visit live objects in old region
180 card_visitor(card_ptr, region);
181 }
182 }
183 }
184 }
185
186 template <typename LockConfigT>
187 template <bool need_lock>
GetRefRegions()188 PandaUnorderedSet<Region *> *RemSet<LockConfigT>::GetRefRegions()
189 {
190 os::memory::LockHolder lock(rem_set_lock_);
191 return &ref_regions_;
192 }
193
194 template <typename LockConfigT>
195 template <bool need_lock>
AddRefRegion(Region * region)196 void RemSet<LockConfigT>::AddRefRegion(Region *region)
197 {
198 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
199 ref_regions_.insert(region);
200 }
201
202 template <typename LockConfigT>
203 template <bool need_lock>
RemoveFromRegion(Region * region)204 void RemSet<LockConfigT>::RemoveFromRegion(Region *region)
205 {
206 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
207 auto it = regions_.find(region);
208 if (it == regions_.end()) {
209 return;
210 }
211 allocator_->Delete(it->second);
212 regions_.erase(it);
213 }
214
215 template <typename LockConfigT>
216 template <bool need_lock>
RemoveRefRegion(Region * region)217 void RemSet<LockConfigT>::RemoveRefRegion(Region *region)
218 {
219 os::memory::LockHolder<LockConfigT, need_lock> lock(rem_set_lock_);
220 ref_regions_.erase(region);
221 }
222
223 template <typename LockConfigT>
Dump(std::ostream & out)224 void RemSet<LockConfigT>::Dump(std::ostream &out)
225 {
226 os::memory::LockHolder lock(rem_set_lock_);
227 out << *region_ << ": From";
228 for (auto entry : regions_) {
229 CardList *cards = entry.second;
230 if (cards != nullptr) {
231 for (CardPtr card : *cards) {
232 if (entry.first->HasFlag(RegionFlag::IS_LARGE_OBJECT)) {
233 out << " H-";
234 } else if (entry.first->HasFlag(RegionFlag::IS_NONMOVABLE)) {
235 out << " NM-";
236 } else if (entry.first->HasFlag(RegionFlag::IS_OLD)) {
237 out << " T-";
238 } else {
239 out << " Y-";
240 }
241 out << std::hex << "[" << card_table_->GetCardStartAddress(card) << "-"
242 << card_table_->GetCardEndAddress(card) << "]";
243 }
244 }
245 }
246 out << " To:";
247 for (auto reg : ref_regions_) {
248 out << " " << *reg;
249 }
250 out << std::dec;
251 }
252
253 } // namespace panda::mem
254
255 #endif // PANDA_MEM_GC_G1_REM_SET_INL_H
256