File indexing completed on 2024-05-05 04:38:10
0001 /* 0002 SPDX-FileCopyrightText: 2009 David Nolden <david.nolden.kdevelop@art-master.de> 0003 SPDX-FileCopyrightText: 2020 Igor Kushnir <igorkuo@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "referencecounting.h" 0009 #include "itemrepository.h" 0010 0011 #include <QAtomicInt> 0012 0013 #include <algorithm> 0014 0015 namespace KDevelop { 0016 void DUChainReferenceCounting::Interval::assign(Pointer newStart, unsigned newSize) noexcept 0017 { 0018 start = newStart; 0019 size = newSize; 0020 refCount = 1; 0021 } 0022 0023 auto DUChainReferenceCounting::findInterval(Pointer start, unsigned size) noexcept -> Interval* 0024 { 0025 return std::find_if(intervals, intervals + count, [start, size](Interval interval) { 0026 return interval.start == start && interval.size == size; 0027 }); 0028 } 0029 0030 void DUChainReferenceCounting::enable(Pointer start, unsigned size) 0031 { 0032 auto* const interval = findInterval(start, size); 0033 if (interval == intervals + count) { 0034 if (count == maxIntervalCount) { 0035 qFatal("DUChainReferenceCounting interval count limit of %zu exceeded!", count); 0036 } 0037 // "push_back" 0038 Q_ASSERT(count < maxIntervalCount); 0039 interval->assign(start, size); 0040 ++count; 0041 } else { 0042 Q_ASSERT(interval < intervals + count); 0043 ++interval->refCount; 0044 } 0045 0046 #ifdef TEST_REFERENCE_COUNTING 0047 Q_ASSERT(shouldDo(start)); 0048 Q_ASSERT(shouldDo(start + size - 1)); 0049 #endif 0050 } 0051 0052 void DUChainReferenceCounting::disable(Pointer start, unsigned size) 0053 { 0054 auto* const interval = findInterval(start, size); 0055 Q_ASSERT(interval < intervals + count); 0056 0057 if (interval->refCount == 1) { 0058 // "erase" interval 0059 std::move(interval + 1, intervals + count, interval); 0060 --count; 0061 } else { 0062 Q_ASSERT(interval->refCount > 1); 0063 --interval->refCount; 0064 } 0065 } 0066 0067 void enableDUChainReferenceCounting(const void* start, unsigned size) 0068 { 0069 DUChainReferenceCounting::instance().enable(reinterpret_cast<DUChainReferenceCounting::Pointer>(start), size); 0070 } 0071 0072 void disableDUChainReferenceCounting(const void* start, unsigned size) 0073 { 0074 DUChainReferenceCounting::instance().disable(reinterpret_cast<DUChainReferenceCounting::Pointer>(start), size); 0075 } 0076 } 0077 0078 #ifdef TEST_REFERENCE_COUNTING 0079 0080 QAtomicInt& id() 0081 { 0082 static QAtomicInt& ret(KDevelop::globalItemRepositoryRegistry().getCustomCounter("referencer ids", 1)); 0083 return ret; 0084 } 0085 0086 namespace KDevelop { 0087 ReferenceCountManager::ReferenceCountManager() : m_id(id().fetchAndAddRelaxed(1)) 0088 { 0089 } 0090 0091 struct ReferenceCountItem 0092 { 0093 ///Item entries: 0094 ReferenceCountItem(uint id, uint target) : m_id(id) 0095 , m_targetId(target) 0096 { 0097 } 0098 0099 ReferenceCountItem& operator=(const ReferenceCountItem& rhs) = delete; 0100 0101 //Every item has to implement this function, and return a valid hash. 0102 //Must be exactly the same hash value as ReferenceCountItemRequest::hash() has returned while creating the item. 0103 unsigned int hash() const 0104 { 0105 return KDevHash() << m_id << m_targetId; 0106 } 0107 0108 //Every item has to implement this function, and return the complete size this item takes in memory. 0109 //Must be exactly the same value as ReferenceCountItemRequest::itemSize() has returned while creating the item. 0110 unsigned short int itemSize() const 0111 { 0112 return sizeof(ReferenceCountItem); 0113 } 0114 0115 uint m_id; 0116 uint m_targetId; 0117 0118 ///Request entries: 0119 enum { 0120 AverageSize = 8 0121 }; 0122 0123 void createItem(ReferenceCountItem* item) const 0124 { 0125 * item = *this; 0126 } 0127 static void destroy(ReferenceCountItem* /*item*/, AbstractItemRepository&) 0128 { 0129 } 0130 0131 static bool persistent(const ReferenceCountItem*) 0132 { 0133 return true; 0134 } 0135 0136 bool equals(const ReferenceCountItem* item) const 0137 { 0138 return m_id == item->m_id && m_targetId == item->m_targetId; 0139 } 0140 }; 0141 0142 static RepositoryManager<ItemRepository<ReferenceCountItem, ReferenceCountItem, false, true, 0143 sizeof(ReferenceCountItem)>, false>& references() 0144 { 0145 static RepositoryManager<ItemRepository<ReferenceCountItem, ReferenceCountItem, false, true, 0146 sizeof(ReferenceCountItem)>, false> referencesObject("Reference Count Debugging"); 0147 return referencesObject; 0148 } 0149 static RepositoryManager<ItemRepository<ReferenceCountItem, ReferenceCountItem, false, true, 0150 sizeof(ReferenceCountItem)>, false>& oldReferences() 0151 { 0152 static RepositoryManager<ItemRepository<ReferenceCountItem, ReferenceCountItem, false, true, 0153 sizeof(ReferenceCountItem)>, false> oldReferencesObject("Old Reference Count Debugging"); 0154 return oldReferencesObject; 0155 } 0156 0157 void KDevelop::initReferenceCounting() 0158 { 0159 references(); 0160 oldReferences(); 0161 } 0162 0163 ReferenceCountManager::~ReferenceCountManager() 0164 { 0165 //Make sure everything is cleaned up when the object is destroyed 0166 // Q_ASSERT(!references().contains(m_id)); 0167 } 0168 0169 ReferenceCountManager::ReferenceCountManager(const ReferenceCountManager& rhs) : m_id(id().fetchAndAddRelaxed(1)) 0170 { 0171 //New id 0172 } 0173 0174 ReferenceCountManager& ReferenceCountManager::ReferenceCountManager::operator=(const ReferenceCountManager& rhs) 0175 { 0176 //Keep id 0177 return *this; 0178 } 0179 0180 // bool ReferenceCountManager::hasReferenceCount() const { 0181 // return references->findIndex(ReferenceCountItem); 0182 // } 0183 0184 void ReferenceCountManager::increase(uint& ref, uint targetId) 0185 { 0186 Q_ASSERT(shouldDoDUChainReferenceCounting(this)); 0187 Q_ASSERT(!references->findIndex(ReferenceCountItem(m_id, targetId))); 0188 ++ref; 0189 0190 { 0191 int oldIndex = oldReferences->findIndex(ReferenceCountItem(m_id, targetId)); 0192 if (oldIndex) 0193 oldReferences->deleteItem(oldIndex); 0194 } 0195 0196 Q_ASSERT(references->index(ReferenceCountItem(m_id, targetId))); 0197 } 0198 0199 void ReferenceCountManager::decrease(uint& ref, uint targetId) 0200 { 0201 Q_ASSERT(ref > 0); 0202 Q_ASSERT(shouldDoDUChainReferenceCounting(this)); 0203 Q_ASSERT(!oldReferences->findIndex(ReferenceCountItem(m_id, targetId))); 0204 uint refIndex = references->findIndex(ReferenceCountItem(m_id, targetId)); 0205 Q_ASSERT(refIndex); 0206 --ref; 0207 references->deleteItem(refIndex); 0208 oldReferences->index(ReferenceCountItem(m_id, targetId)); 0209 } 0210 } 0211 0212 #else 0213 namespace KDevelop { 0214 void initReferenceCounting() 0215 { 0216 } 0217 } 0218 #endif