• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef PANDA_RUNTIME_MEM_REFERENCES_STORAGE_H
16 #define PANDA_RUNTIME_MEM_REFERENCES_STORAGE_H
17 
18 #include "runtime/include/object_header.h"
19 #include "runtime/mem/frame_allocator.h"
20 #include "runtime/mem/refstorage/reference.h"
21 #include "runtime/mem/internal_allocator.h"
22 #include "ref_block.h"
23 
24 namespace panda {
25 class ObjectHeader;
26 namespace mem {
27 class Reference;
28 namespace test {
29 class ReferenceStorageTest;
30 }  // namespace test
31 }  // namespace mem
32 }  // namespace panda
33 
34 namespace panda::mem {
35 
36 /**
37  * Storage stores all References for proper interaction with GC.
38  */
39 class ReferenceStorage {
40 public:
41     static_assert(offsetof(RefBlock, refs_) == 0);
42 
43     explicit ReferenceStorage(GlobalObjectStorage *global_storage, mem::InternalAllocatorPtr allocator,
44                               bool ref_check_validate);
45 
46     ~ReferenceStorage();
47 
48     bool Init();
49 
50     static Reference::ObjectType GetObjectType(const Reference *ref);
51 
NewStackRef(ObjectHeader ** object_ptr)52     [[nodiscard]] static Reference *NewStackRef(ObjectHeader **object_ptr)
53     {
54         ASSERT(object_ptr != nullptr);
55         if (*object_ptr == nullptr) {
56             return nullptr;
57         }
58         return Reference::Create(ToUintPtr(object_ptr), Reference::ObjectType::STACK);
59     }
60 
61     [[nodiscard]] Reference *NewRef(const ObjectHeader *object, Reference::ObjectType object_type);
62 
63     void RemoveRef(const Reference *ref);
64 
65     [[nodiscard]] ObjectHeader *GetObject(const Reference *ref);
66 
67     /**
68      * Creates a new frame with at least given number of local references which can be created in this frame.
69      *
70      * @param capacity minimum number of local references in the frame.
71      * @return true if frame was successful allocated, false otherwise.
72      */
73     bool PushLocalFrame(uint32_t capacity);
74 
75     /**
76      * Pops the last frame, frees all local references in this frame and moves given reference to the previous frame and
77      * return it's new reference. Should be NULL if you don't want to return any value to previous frame.
78      *
79      * @param result reference which you want to return in the previous frame.
80      * @return new reference in the previous frame for given reference.
81      */
82     Reference *PopLocalFrame(const Reference *result);
83 
84     /**
85      * Ensure that capacity in current frame can contain at least `size` references.
86      * @param capacity minimum number of references for this frame
87      * @return true if current frame can store at least `size` references, false otherwise.
88      */
89     bool EnsureLocalCapacity(size_t capacity);
90 
91     /**
92      * Get all objects in global & local storage. Use for debugging only
93      */
94     PandaVector<ObjectHeader *> GetAllObjects();
95 
96     void VisitObjects(const GCRootVisitor &gc_root_visitor, mem::RootType rootType);
97 
98     /**
99      * Update pointers to moved Objects in local storage
100      */
101     void UpdateMovedRefs();
102 
103     /**
104      * Dump the last several local references info(max MAX_DUMP_LOCAL_NUMS).
105      */
106     void DumpLocalRef();
107 
108     /**
109      * Dump the top MAX_DUMP_LOCAL_NUMS(if exists) classes of local references.
110      */
111     void DumpLocalRefClasses();
112     bool IsValidRef(const Reference *ref);
113     void SetRefCheckValidate(bool ref_check_validate);
114 
115 private:
116     NO_COPY_SEMANTIC(ReferenceStorage);
117     NO_MOVE_SEMANTIC(ReferenceStorage);
118 
119     ObjectHeader *FindLocalObject(const Reference *ref);
120 
121     RefBlock *CreateBlock();
122 
123     void RemoveBlock(RefBlock *block);
124 
125     static constexpr size_t MAX_DUMP_LOCAL_NUMS = 10;
126 
127     static constexpr Alignment BLOCK_ALIGNMENT = Alignment::LOG_ALIGN_8;
128     static constexpr size_t BLOCK_SIZE = sizeof(RefBlock);
129 
130     static_assert(GetAlignmentInBytes(BLOCK_ALIGNMENT) >= BLOCK_SIZE);
131     static_assert(GetAlignmentInBytes(static_cast<Alignment>(BLOCK_ALIGNMENT - 1)) <= BLOCK_SIZE);
132 
133     static constexpr size_t MAX_STORAGE_SIZE = 128_MB;
134     static constexpr size_t MAX_STORAGE_BLOCK_COUNT = MAX_STORAGE_SIZE / BLOCK_SIZE;
135 
136     using StorageFrameAllocator = mem::FrameAllocator<BLOCK_ALIGNMENT, false>;
137 
138     GlobalObjectStorage *global_storage_;
139     mem::InternalAllocatorPtr internal_allocator_;
140     PandaVector<RefBlock *> *local_storage_ {nullptr};
141     StorageFrameAllocator *frame_allocator_ {nullptr};
142     size_t blocks_count_ {0};
143     // TODO(alovkov): remove it when storage will be working over mmap
144     RefBlock *cached_block_ {nullptr};
145 
146     bool ref_check_validate_;
147     // private methods for test purpose only
148     size_t GetGlobalObjectStorageSize();
149 
150     size_t GetLocalObjectStorageSize();
151 
152     void RemoveAllLocalRefs();
153 
154     bool StackReferenceCheck(const Reference *stack_ref);
155 
156     friend class panda::mem::test::ReferenceStorageTest;
157 };
158 
159 /**
160  * Handle the reference of object that might be moved by gc, note that
161  * it should be only used in Managed code(with ScopedObjectFix).
162  */
163 class ReferenceHandle {
164 public:
165     ~ReferenceHandle() = default;
166 
167     template <typename T>
168     ReferenceHandle(const ReferenceHandle &rhs, T *object, Reference::ObjectType type = Reference::ObjectType::LOCAL)
169         : rs_(rhs.rs_), ref_(rs_->NewRef(reinterpret_cast<ObjectHeader *>(object), type))
170     {
171         ASSERT(ref_ != nullptr);
172     }
173 
174     template <typename T>
175     ReferenceHandle(ReferenceStorage *rs, T *object, Reference::ObjectType type = Reference::ObjectType::LOCAL)
rs_(rs)176         : rs_(rs), ref_(rs_->NewRef(reinterpret_cast<ObjectHeader *>(object), type))
177     {
178         ASSERT(ref_ != nullptr);
179     }
180 
181     template <typename T>
GetObject()182     T *GetObject()
183     {
184         return reinterpret_cast<T *>(rs_->GetObject(ref_));
185     }
186 
187     template <typename T>
188     Reference *NewRef(T *object, bool release_old = true, Reference::ObjectType type = Reference::ObjectType::LOCAL)
189     {
190         if (release_old && ref_ != nullptr) {
191             rs_->RemoveRef(ref_);
192         }
193         ref_ = rs_->NewRef(reinterpret_cast<ObjectHeader *>(object), type);
194         return ref_;
195     }
196 
197     /**
198      * Remove a reference explicitly,
199      * suggest not doing this unless the ReferenceStorage will be out of capacity,
200      * and the reference is created in caller scope and not used by any other place
201      */
RemoveRef()202     void RemoveRef()
203     {
204         rs_->RemoveRef(ref_);
205         ref_ = nullptr;
206     }
207 
208 private:
209     ReferenceStorage *rs_;
210     Reference *ref_;
211     NO_COPY_SEMANTIC(ReferenceHandle);
212     NO_MOVE_SEMANTIC(ReferenceHandle);
213 };
214 
215 }  // namespace panda::mem
216 
217 #endif  // PANDA_RUNTIME_MEM_REFERENCES_STORAGE_H
218