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