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()26 RemSet<LockConfigT>::~RemSet()
27 {
28 Clear();
29 }
30
31 template <typename LockConfigT>
32 template <bool NEED_LOCK>
AddRef(const ObjectHeader * fromObjAddr,size_t offset)33 void RemSet<LockConfigT>::AddRef(const ObjectHeader *fromObjAddr, size_t offset)
34 {
35 ASSERT(fromObjAddr != nullptr);
36 auto ref = ToUintPtr(fromObjAddr) + offset;
37 auto bitmapBeginAddr = ref & ~DEFAULT_REGION_MASK;
38 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(remSetLock_);
39 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
40 bitmaps_[bitmapBeginAddr].Set(GetIdxInBitmap(ref, bitmapBeginAddr));
41 }
42
43 template <typename LockConfigT>
Clear()44 void RemSet<LockConfigT>::Clear()
45 {
46 os::memory::LockHolder lock(remSetLock_);
47 bitmaps_.clear();
48 refRegions_.clear();
49 }
50
51 /* static */
52 template <typename LockConfigT>
53 template <bool NEED_LOCK>
InvalidateRegion(Region * invalidRegion)54 void RemSet<LockConfigT>::InvalidateRegion(Region *invalidRegion)
55 {
56 RemSet<> *invalidRemset = invalidRegion->GetRemSet();
57 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(invalidRemset->remSetLock_);
58
59 for (Region *refReg : invalidRemset->refRegions_) {
60 refReg->GetRemSet()->RemoveFromRegion<NEED_LOCK>(invalidRegion);
61 }
62
63 for (auto entry : invalidRemset->bitmaps_) {
64 auto bitmapBeginAddr = entry.first;
65 auto *fromRegion = AddrToRegion(ToVoidPtr(bitmapBeginAddr));
66 fromRegion->GetRemSet()->RemoveRefRegion<NEED_LOCK>(invalidRegion);
67 }
68 }
69
70 /* static */
71 template <typename LockConfigT>
72 template <bool NEED_LOCK>
InvalidateRefsFromRegion(Region * invalidRegion)73 void RemSet<LockConfigT>::InvalidateRefsFromRegion(Region *invalidRegion)
74 {
75 RemSet<> *invalidRemset = invalidRegion->GetRemSet();
76 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(invalidRemset->remSetLock_);
77 for (Region *refReg : invalidRemset->refRegions_) {
78 refReg->GetRemSet()->RemoveFromRegion<NEED_LOCK>(invalidRegion);
79 }
80 invalidRemset->refRegions_.clear();
81 }
82
83 /* static */
84 template <typename LockConfigT>
85 template <bool NEED_LOCK>
AddRefWithAddr(const ObjectHeader * objAddr,size_t offset,const ObjectHeader * valueAddr)86 void RemSet<LockConfigT>::AddRefWithAddr(const ObjectHeader *objAddr, size_t offset, const ObjectHeader *valueAddr)
87 {
88 auto *fromRegion = ObjectToRegion(objAddr);
89 auto *toRegion = ObjectToRegion(valueAddr);
90 // TSAN thinks that we can have a data race here when we get region or getRemSet from region, because we don't have
91 // synchronization between these events. In reality it's impossible, because if we get write from/to region it
92 // should be created already by allocator in mutator thread, and only then writes happens.
93 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN();
94 ASSERT(fromRegion != nullptr);
95 ASSERT(fromRegion->GetRemSet() != nullptr);
96 ASSERT(toRegion != nullptr);
97 ASSERT_PRINT(toRegion->GetRemSet() != nullptr,
98 "region " << toRegion << ", obj " << objAddr << ", value " << valueAddr);
99
100 toRegion->GetRemSet()->AddRef<NEED_LOCK>(objAddr, offset);
101 fromRegion->GetRemSet()->AddRefRegion<NEED_LOCK>(toRegion);
102 TSAN_ANNOTATE_IGNORE_WRITES_END();
103 }
104
105 template <typename LockConfigT>
106 template <typename RegionPred, typename MemVisitor>
Iterate(const RegionPred & regionPred,const MemVisitor & visitor)107 inline void RemSet<LockConfigT>::Iterate(const RegionPred ®ionPred, const MemVisitor &visitor)
108 {
109 for (auto &[bitmap_begin_addr, bitmap] : bitmaps_) {
110 auto *region = AddrToRegion(ToVoidPtr(bitmap_begin_addr));
111 if (regionPred(region)) {
112 MemRange bitmapRange(bitmap_begin_addr, bitmap_begin_addr + DEFAULT_REGION_SIZE);
113 bitmap.Iterate(bitmapRange, [region, visitor](const MemRange &range) { visitor(region, range); });
114 }
115 }
116 }
117
118 template <typename LockConfigT>
119 template <typename Visitor>
IterateOverObjects(const Visitor & visitor)120 inline void RemSet<LockConfigT>::IterateOverObjects(const Visitor &visitor)
121 {
122 auto regionPred = []([[maybe_unused]] Region *region) { return true; };
123 Iterate(regionPred, [visitor](Region *region, const MemRange &range) {
124 region->GetLiveBitmap()->IterateOverMarkedChunkInRange(
125 ToVoidPtr(range.GetStartAddress()), ToVoidPtr(range.GetEndAddress()),
126 [visitor](void *mem) { visitor(static_cast<ObjectHeader *>(mem)); });
127 });
128 }
129
130 template <typename LockConfigT>
131 template <bool NEED_LOCK>
GetRefRegions()132 PandaUnorderedSet<Region *> *RemSet<LockConfigT>::GetRefRegions()
133 {
134 os::memory::LockHolder lock(remSetLock_);
135 return &refRegions_;
136 }
137
138 template <typename LockConfigT>
139 template <bool NEED_LOCK>
AddRefRegion(Region * region)140 void RemSet<LockConfigT>::AddRefRegion(Region *region)
141 {
142 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(remSetLock_);
143 refRegions_.insert(region);
144 }
145
146 template <typename LockConfigT>
147 template <bool NEED_LOCK>
RemoveFromRegion(Region * region)148 void RemSet<LockConfigT>::RemoveFromRegion(Region *region)
149 {
150 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(remSetLock_);
151 for (auto bitmapBeginAddr = ToUintPtr(region); bitmapBeginAddr < region->End();
152 bitmapBeginAddr += DEFAULT_REGION_SIZE) {
153 bitmaps_.erase(bitmapBeginAddr);
154 }
155 }
156
157 template <typename LockConfigT>
158 template <bool NEED_LOCK>
RemoveRefRegion(Region * region)159 void RemSet<LockConfigT>::RemoveRefRegion(Region *region)
160 {
161 os::memory::LockHolder<LockConfigT, NEED_LOCK> lock(remSetLock_);
162 refRegions_.erase(region);
163 }
164
165 template <typename LockConfigT>
GetIdxInBitmap(uintptr_t addr,uintptr_t bitmapBeginAddr)166 size_t RemSet<LockConfigT>::GetIdxInBitmap(uintptr_t addr, uintptr_t bitmapBeginAddr)
167 {
168 size_t memSize = DEFAULT_REGION_SIZE / Bitmap::GetNumBits();
169 ASSERT(bitmapBeginAddr <= addr && addr < bitmapBeginAddr + DEFAULT_REGION_SIZE);
170 return (addr - bitmapBeginAddr) / memSize;
171 }
172
173 template <typename LockConfigT>
Dump(std::ostream & out)174 void RemSet<LockConfigT>::Dump(std::ostream &out)
175 {
176 os::memory::LockHolder lock(remSetLock_);
177 auto pred = []([[maybe_unused]] Region *region) { return true; };
178 Iterate(pred, [&out](Region *region, const MemRange &range) {
179 if (region->HasFlag(RegionFlag::IS_LARGE_OBJECT)) {
180 out << " H";
181 } else if (region->HasFlag(RegionFlag::IS_NONMOVABLE)) {
182 out << " NM";
183 } else if (region->HasFlag(RegionFlag::IS_OLD)) {
184 out << " T";
185 } else {
186 out << " Y";
187 }
188 out << "[" << ToVoidPtr(range.GetStartAddress()) << "-" << ToVoidPtr(range.GetEndAddress()) << "]";
189 });
190 out << " To:";
191 for (auto reg : refRegions_) {
192 out << " " << *reg;
193 }
194 out << std::dec;
195 }
196
197 } // namespace panda::mem
198
199 #endif // PANDA_MEM_GC_G1_REM_SET_INL_H
200