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 #include "ref_block.h"
16
17 namespace panda::mem {
18
RefBlock(RefBlock * prev)19 RefBlock::RefBlock(RefBlock *prev)
20 {
21 slots_ = START_VALUE;
22 prev_block_ = prev;
23 }
24
Reset(RefBlock * prev)25 void RefBlock::Reset(RefBlock *prev)
26 {
27 slots_ = START_VALUE;
28 prev_block_ = 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 ref_ptr = ToUintPtr(ref);
47 auto block_ptr = ToUintPtr(this);
48 auto index = (ref_ptr - block_ptr) / 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 & gc_root_visitor,mem::RootType rootType)54 void RefBlock::VisitObjects(const GCRootVisitor &gc_root_visitor, 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 object_pointer = block->refs_[index];
63 auto *obj = object_pointer.ReinterpretCast<ObjectHeader *>();
64 ASSERT(obj->ClassAddr<BaseClass>() != nullptr);
65 LOG(DEBUG, GC) << " Found root from ref-storage: " << mem::GetDebugInfoAboutObject(obj);
66 gc_root_visitor({rootType, obj});
67 }
68 }
69 }
70 }
71
UpdateMovedRefs()72 void RefBlock::UpdateMovedRefs()
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 object_pointer = block->refs_[index];
84 auto *object = object_pointer.ReinterpretCast<ObjectHeader *>();
85 auto obj = reinterpret_cast<ObjectHeader *>(object);
86
87 if (!obj->IsForwarded()) {
88 continue;
89 }
90
91 LOG(DEBUG, GC) << " Update pointer for obj: " << mem::GetDebugInfoAboutObject(obj);
92 ObjectHeader *forward_address = GetForwardAddress(obj);
93 block->refs_[index] = reinterpret_cast<ObjectHeader *>(forward_address);
94 }
95 }
96 }
97
98 // used only for dumping and tests
GetAllReferencesInFrame()99 PandaVector<Reference *> RefBlock::GetAllReferencesInFrame()
100 {
101 PandaVector<Reference *> refs;
102 for (auto *block : *this) {
103 if (block->IsEmpty()) {
104 continue;
105 }
106 for (size_t index = 0; index < REFS_IN_BLOCK; index++) {
107 if (block->IsBusyIndex(index)) {
108 auto *current_ref = reinterpret_cast<Reference *>(&block->refs_[index]);
109 refs.push_back(current_ref);
110 }
111 }
112 }
113 return refs;
114 }
115
GetFreeIndex()116 uint8_t RefBlock::GetFreeIndex()
117 {
118 ASSERT(!IsFull());
119 auto res = Ffs(slots_) - 1;
120 #ifndef NDEBUG
121 uint8_t index = 0;
122 while (IsBusyIndex(index)) {
123 index++;
124 }
125 ASSERT(index == res);
126 #endif
127 return res;
128 }
129
Set(uint8_t index,const ObjectHeader * object)130 void RefBlock::Set(uint8_t index, const ObjectHeader *object)
131 {
132 ASSERT(IsFreeIndex(index));
133 ASAN_UNPOISON_MEMORY_REGION(refs_[index], sizeof(refs_[index]));
134 refs_[index] = object;
135 slots_ &= ~(static_cast<uint64_t>(1U) << index);
136 }
137
IsFreeIndex(uint8_t index)138 bool RefBlock::IsFreeIndex(uint8_t index)
139 {
140 return !IsBusyIndex(index);
141 }
142
IsBusyIndex(uint8_t index)143 bool RefBlock::IsBusyIndex(uint8_t index)
144 {
145 return ((slots_ >> index) & 1U) == 0;
146 }
147
PrintBlock()148 void RefBlock::PrintBlock()
149 {
150 auto refs = GetAllReferencesInFrame();
151 for (const auto &ref : refs) {
152 std::cout << ref << " ";
153 }
154 }
155
156 } // namespace panda::mem
157