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