• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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