1 /**
2 * Copyright (c) 2021-2025 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 #include "ref_block.h"
16
17 namespace ark::mem {
18
RefBlock(RefBlock * prev)19 RefBlock::RefBlock(RefBlock *prev)
20 {
21 slots_ = START_VALUE;
22 prevBlock_ = prev;
23 }
24
Reset(RefBlock * prev)25 void RefBlock::Reset(RefBlock *prev)
26 {
27 slots_ = START_VALUE;
28 prevBlock_ = prev;
29 }
30
AddRef(const ObjectHeader * object,Reference::ObjectType type)31 Reference *RefBlock::AddRef(const ObjectHeader *object, Reference::ObjectType type)
32 {
33 ASSERT(!IsFull());
34 uint8_t index = GetFreeIndex();
35 Set(index, object);
36 auto *ref = reinterpret_cast<Reference *>(&refs_[index]);
37 ref = Reference::SetType(ref, type);
38 return ref;
39 }
40
Remove(const Reference * ref)41 void RefBlock::Remove(const Reference *ref)
42 {
43 ASSERT(!IsEmpty());
44 ref = Reference::GetRefWithoutType(ref);
45
46 auto refPtr = ToUintPtr(ref);
47 auto blockPtr = ToUintPtr(this);
48 auto index = (refPtr - blockPtr) / sizeof(ObjectPointer<ObjectHeader>);
49 ASSERT(IsBusyIndex(index));
50 slots_ |= static_cast<uint64_t>(1U) << index;
51 ASAN_POISON_MEMORY_REGION(refs_[index], sizeof(refs_[index]));
52 }
53
VisitObjects(const GCRootVisitor & gcRootVisitor,mem::RootType rootType)54 void RefBlock::VisitObjects(const GCRootVisitor &gcRootVisitor, mem::RootType rootType)
55 {
56 for (auto *block : *this) {
57 if (block->IsEmpty()) {
58 continue;
59 }
60 for (size_t index = 0; index < REFS_IN_BLOCK; index++) {
61 if (block->IsBusyIndex(index)) {
62 auto objectPointer = block->refs_[index];
63 auto *obj = objectPointer.ReinterpretCast<ObjectHeader *>();
64 ASSERT(obj->ClassAddr<BaseClass>() != nullptr);
65 LOG(DEBUG, GC) << " Found root from ref-storage: " << mem::GetDebugInfoAboutObject(obj);
66 gcRootVisitor({rootType, obj});
67 }
68 }
69 }
70 }
71
UpdateMovedRefs(const GCRootUpdater & gcRootUpdater)72 void RefBlock::UpdateMovedRefs([[maybe_unused]] const GCRootUpdater &gcRootUpdater)
73 {
74 for (auto *block : *this) {
75 if (block->IsEmpty()) {
76 continue;
77 }
78 for (size_t index = 0; index < REFS_IN_BLOCK; index++) {
79 if (!block->IsBusyIndex(index)) {
80 continue;
81 }
82
83 auto *obj = block->refs_[index].ReinterpretCast<ObjectHeader *>();
84
85 if (!gcRootUpdater(&obj)) {
86 continue;
87 }
88
89 auto *movedObject = block->refs_[index].ReinterpretCast<ObjectHeader *>();
90
91 LOG_IF(obj != movedObject, DEBUG, GC) << " Update pointer for obj: " << mem::GetDebugInfoAboutObject(obj);
92 block->refs_[index] = obj;
93 }
94 }
95 }
96
97 // used only for dumping and tests
GetAllReferencesInFrame()98 PandaVector<Reference *> RefBlock::GetAllReferencesInFrame()
99 {
100 PandaVector<Reference *> refs;
101 for (auto *block : *this) {
102 if (block->IsEmpty()) {
103 continue;
104 }
105 for (size_t index = 0; index < REFS_IN_BLOCK; index++) {
106 if (block->IsBusyIndex(index)) {
107 auto *currentRef = reinterpret_cast<Reference *>(&block->refs_[index]);
108 refs.push_back(currentRef);
109 }
110 }
111 }
112 return refs;
113 }
114
GetFreeIndex()115 uint8_t RefBlock::GetFreeIndex()
116 {
117 ASSERT(!IsFull());
118 auto res = Ffs(slots_) - 1;
119 #ifndef NDEBUG
120 uint8_t index = 0;
121 while (IsBusyIndex(index)) {
122 index++;
123 }
124 ASSERT(index == res);
125 #endif
126 return res;
127 }
128
Set(uint8_t index,const ObjectHeader * object)129 void RefBlock::Set(uint8_t index, const ObjectHeader *object)
130 {
131 ASSERT(IsFreeIndex(index));
132 ASAN_UNPOISON_MEMORY_REGION(refs_[index], sizeof(refs_[index]));
133 refs_[index] = object;
134 slots_ &= ~(static_cast<uint64_t>(1U) << index);
135 }
136
IsFreeIndex(uint8_t index)137 bool RefBlock::IsFreeIndex(uint8_t index)
138 {
139 return !IsBusyIndex(index);
140 }
141
IsBusyIndex(uint8_t index)142 bool RefBlock::IsBusyIndex(uint8_t index)
143 {
144 return ((slots_ >> index) & 1U) == 0;
145 }
146
PrintBlock()147 void RefBlock::PrintBlock()
148 {
149 auto refs = GetAllReferencesInFrame();
150 for (const auto &ref : refs) {
151 std::cout << ref << " ";
152 }
153 }
154
155 } // namespace ark::mem
156