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