[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: KDE/kdevplatform/language/duchain
From: David Nolden <david.nolden.kde () art-master ! de>
Date: 2008-11-30 22:57:15
Message-ID: 1228085835.103122.309.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 891018 by zwabel:
Make the destructor/constructor calls in the duchain data classes "persistent". This \
means that whenever a duchain item data is copied, the copy-constructor is called, \
and whenever a duchain item data is deleted the destructor is called. The important \
trick: The destructor is _not_ called when the duchain item has been stored to disk. \
Then, only the freeDynamicData() function is called, which releases used memory. This \
allows doing easy and convenient persistent C++-like reference-counting in the data \
classes, relying purely on the constructors and destructors.
M +4 -2 appendedlist.h
M +13 -8 declaration.cpp
M +24 -14 duchain.cpp
M +7 -7 duchainbase.cpp
M +16 -0 duchainbase.h
M +7 -0 duchainregister.cpp
M +11 -0 duchainregister.h
M +2 -0 ducontext.cpp
M +4 -4 topducontext.cpp
M +9 -1 topducontextdynamicdata.cpp
M +5 -0 topducontextdynamicdata.h
M +3 -0 types/typesystemdata.h
--- trunk/KDE/kdevplatform/language/duchain/appendedlist.h #891017:891018
@@ -200,13 +200,15 @@
///use this if the class does not have a base class that also uses appended lists
#define START_APPENDED_LISTS(container) \
-unsigned int offsetBehindBase() const { return 0; }
+unsigned int offsetBehindBase() const { return 0; } \
+void freeDynamicData() { freeAppendedLists(); }
///Use this if one of the base-classes of the container also has the appended lists \
interfaces implemented. ///To reduce the probability of future problems, you should \
give the direct base class this one inherits from. ///@note: Multiple inheritance is \
not supported, however it will work ok if only one of the base-classes uses appended \
lists. #define START_APPENDED_LISTS_BASE(container, base) \
-unsigned int offsetBehindBase() const { return base :: offsetBehindLastList(); }
+unsigned int offsetBehindBase() const { return base :: offsetBehindLastList(); } \
+void freeDynamicData() { freeAppendedLists(); base::freeDynamicData(); }
#define APPENDED_LIST_COMMON(container, type, name) \
--- trunk/KDE/kdevplatform/language/duchain/declaration.cpp #891017:891018
@@ -140,8 +140,12 @@
Declaration::~Declaration()
{
+ uint oldOwnIndex = m_indexInTopContext;
+
+ TopDUContext* topContext = this->topContext();
+
//Only perform the actions when the top-context isn't being deleted, or when it \
hasn't been stored to disk
- if(!topContext()->deleting() || !topContext()->isOnDisk()) {
+ if(!topContext->deleting() || !topContext->isOnDisk()) {
DUCHAIN_D_DYNAMIC(Declaration);
// Inserted by the builder after construction has finished.
if( d->m_internalContext.context() )
@@ -156,20 +160,21 @@
d->m_inSymbolTable = false;
}
- // If the parent-context already has dynamic data, like for example any \
temporary context,
- // always delete the declaration, to not create crashes within more complex code \
like C++ template stuff.
- if (context() && !d_func()->m_anonymousInContext) {
- if(!topContext()->deleting() || !topContext()->isOnDisk() || \
context()->d_func()->isDynamic())
- Q_ASSERT(context()->m_dynamicData->removeDeclaration(this));
- }
+ // If the parent-context already has dynamic data, like for example any temporary \
context, + // always delete the declaration, to not create crashes within more \
complex code like C++ template stuff. + if (context() && \
!d_func()->m_anonymousInContext) { + if(!topContext->deleting() || \
!topContext->isOnDisk() || context()->d_func()->isDynamic()) + \
Q_ASSERT(context()->m_dynamicData->removeDeclaration(this)); + }
clearOwnIndex();
- if(!topContext()->deleting() || !topContext()->isOnDisk()) {
+ if(!topContext->deleting() || !topContext->isOnDisk()) {
setContext(0);
setAbstractType(AbstractType::Ptr());
}
+ Q_ASSERT(d_func()->isDynamic() == (!topContext->deleting() || \
!topContext->isOnDisk() || \
topContext->m_dynamicData->isTemporaryDeclarationIndex(oldOwnIndex))); \
//DUChain::declarationChanged(this, DUChainObserver::Deletion, \
DUChainObserver::NotApplicable); }
--- trunk/KDE/kdevplatform/language/duchain/duchain.cpp #891017:891018
@@ -127,7 +127,7 @@
size_t itemSize() const {
return sizeof(EnvironmentInformationItem) + \
DUChainItemSystem::self().dynamicSize(*m_file->d_func()); }
-
+
void createItem(EnvironmentInformationItem* item) const {
new (item) EnvironmentInformationItem(m_index, \
DUChainItemSystem::self().dynamicSize(*m_file->d_func()));
@@ -340,13 +340,16 @@
Q_ASSERT(info->d_func()->classId);
}
- ///The item must managed currently
+ ///The item must be managed currently
void removeEnvironmentInformation(ParsingEnvironmentFilePointer info) {
+ info->makeDynamic(); //By doing this, we make sure the data is actually being \
destroyed in the destructor +
bool removed = (bool)m_fileEnvironmentInformations.remove(info->url(), info);
uint index = m_environmentInfo.findIndex(info->indexedTopContext().index());
- if(index)
+ if(index) {
m_environmentInfo.deleteItem(index);
+ }
Q_ASSERT(index || removed);
}
@@ -611,16 +614,20 @@
}
- for(QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator it = \
m_fileEnvironmentInformations.begin(); it != \
m_fileEnvironmentInformations.end(); ) {
- ParsingEnvironmentFile* f = (*it).data();
- Q_ASSERT(f->d_func()->classId);
- if(f->ref == 1) {
- //The ParsingEnvironmentFilePointer is only referenced once. This means \
that it's does not belong to any
- //loaded top-context, so just remove it to save some memory and processing \
time.
- ///@todo use some kind of timeout before removing
- it = m_fileEnvironmentInformations.erase(it);
- }else{
- ++it;
+ if(retries == 0) {
+ //Do this atomically, since we must be sure that _everything_ is already \
saved + for(QMultiMap<IndexedString, ParsingEnvironmentFilePointer>::iterator \
it = m_fileEnvironmentInformations.begin(); it != \
m_fileEnvironmentInformations.end(); ) { + ParsingEnvironmentFile* f = \
(*it).data(); + Q_ASSERT(f->d_func()->classId);
+ if(f->ref == 1) {
+ Q_ASSERT(!f->d_func()->isDynamic()); //It cannot be dynamic, since we \
have stored before + //The ParsingEnvironmentFilePointer is only \
referenced once. This means that it does not belong to any + //loaded \
top-context, so just remove it to save some memory and processing time. + \
///@todo use some kind of timeout before removing + it = \
m_fileEnvironmentInformations.erase(it); + }else{
+ ++it;
+ }
}
}
@@ -825,8 +832,11 @@
branchRemoved(context);
- if(!context->isOnDisk())
+ if(!context->isOnDisk()) {
removeFromEnvironmentManager(context);
+ }else{
+ context->m_dynamicData->store();
+ }
context->deleteSelf();
--- trunk/KDE/kdevplatform/language/duchain/duchainbase.cpp #891017:891018
@@ -70,19 +70,15 @@
void DUChainBase::setData(DocumentRangeObjectData* data)
{
- if(d_func()->m_dynamic)
- //We only delete the data when it's dynamic, because else it is embedded in an \
array in the top-context.
- KDevelop::DUChainItemSystem::self().callDestructor(d_func_dynamic());
+ KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
DocumentRangeObject::setData(data);
}
DUChainBase::~DUChainBase()
{
- if(d_func()->m_dynamic) {
- //We only delete the data when it's dynamic, because else it is embedded in an \
array in the top-context. + if(d_func()->m_dynamic)
KDevelop::DUChainItemSystem::self().callDestructor(d_func_dynamic());
- }
if (m_ptr)
m_ptr->m_base = 0;
@@ -115,8 +111,11 @@
Q_ASSERT(d_ptr);
if(!d_func()->m_dynamic) {
Q_ASSERT(d_func()->classId);
+ DUChainBaseData* newData = DUChainItemSystem::self().cloneData(*d_func());
//We don't delete the previous data, because it's embedded in the top-context \
when it isn't dynamic.
- d_ptr = DUChainItemSystem::self().cloneData(*d_func());
+ //However we do call the destructor, to keep semantic stuff like \
reference-counting within the data class working correctly. + \
KDevelop::DUChainItemSystem::self().callDestructor(static_cast<DUChainBaseData*>(d_ptr));
+ d_ptr = newData;
Q_ASSERT(d_ptr);
Q_ASSERT(d_func()->m_dynamic);
Q_ASSERT(d_func()->classId);
@@ -137,6 +136,7 @@
else
shouldCreateConstantDataStorage.setLocalData(0);
}
+
}
// kate: space-indent on; indent-width 2; tab-width 4; replace-tabs on; \
auto-insert-doxygen on
--- trunk/KDE/kdevplatform/language/duchain/duchainbase.h #891017:891018
@@ -43,6 +43,15 @@
#define DUCHAIN_D(Class) const Class##Data * const d = d_func()
#define DUCHAIN_D_DYNAMIC(Class) Class##Data * const d = d_func_dynamic()
+///@note When a data-item is stored on disk, no destructors of contained items will \
be called while destruction. +///DUChainBase assumes that each item that has constant \
data, is stored on disk. +///However the destructor is called even on constant items, \
when they have been replaced with a dynamic item. +///This tries to keep \
constructor/destructor count consistency persistently, which allows doing static \
reference-counting +///using contained classes in their constructor/destructors(For \
example the class Utils::StorableSet). +///This means that the data of all items that \
are stored to disk _MUST_ be made constant before their destruction. +///This also \
means that every item that is "semantically" deleted, _MUST_ have dynamic data before \
its destruction. +///This also means that DUChainBaseData based items should never be \
cloned using memcpy, but rather always using the copy-constructor, +///even if both \
sides are constant. struct KDEVPLATFORMLANGUAGE_EXPORT DUChainBaseData : public \
DocumentRangeObjectData { DUChainBaseData() : classId(0) {
}
@@ -64,6 +73,11 @@
uint classSize() const;
+ ///This is called whenever the data-object is being deleted memory-wise, but not \
semantically(Which means it stays on disk) + ///Implementations of parent-classes \
must always be called + void freeDynamicData() {
+ }
+
///Used to decide whether a constructed item should create constant data.
///The default is "false", so dynamic data is created by default.
///This is stored thread-locally.
@@ -116,6 +130,8 @@
DUChainBase( DUChainBaseData& dd );
+ ///This must only be used to change the storage-location or \
storage-kind(dynamic/constant) of the data, but + ///the data must always be equal!
virtual void setData(DocumentRangeObjectData*);
protected:
--- trunk/KDE/kdevplatform/language/duchain/duchainregister.cpp #891017:891018
@@ -40,6 +40,13 @@
return m_factories[data->classId]->callDestructor(data);
}
+void DUChainItemSystem::freeDynamicData(KDevelop::DUChainBaseData* data) const {
+ if(uint(m_factories.size()) <= data->classId || m_factories[data->classId] == 0)
+ return;
+ return m_factories[data->classId]->freeDynamicData(data);
+
+}
+
uint DUChainItemSystem::dynamicSize(const DUChainBaseData& data) const {
if(uint(m_factories.size()) <= data.classId || m_factories[data.classId] == 0)
return 0;
--- trunk/KDE/kdevplatform/language/duchain/duchainregister.h #891017:891018
@@ -32,6 +32,7 @@
public:
virtual DUChainBase* create(DUChainBaseData* data) const = 0;
virtual void callDestructor(DUChainBaseData* data) const = 0;
+ virtual void freeDynamicData(DUChainBaseData* data) const = 0;
virtual void copy(const DUChainBaseData& from, DUChainBaseData& to, bool constant) \
const = 0; virtual DUChainBaseData* cloneData(const DUChainBaseData& data) const = \
0; virtual uint dynamicSize(const DUChainBaseData& data) const = 0;
@@ -64,6 +65,11 @@
static_cast<Data*>(data)->~Data();
}
+ void freeDynamicData(DUChainBaseData* data) const {
+ Q_ASSERT(data->classId == T::Identity);
+ static_cast<Data*>(data)->freeDynamicData();
+ }
+
uint dynamicSize(const DUChainBaseData& data) const {
Q_ASSERT(data.classId == T::Identity);
return static_cast<const Data&>(data).dynamicSize();
@@ -133,8 +139,13 @@
size_t dataClassSize(const DUChainBaseData& data) const;
///Calls the destructor, but does not delete anything. This is needed because \
the data classes must not contain virtual members. + ///This should only be called \
when a duchain data-pointer is semantically deleted, eg. when it does not persist on \
disk. void callDestructor(DUChainBaseData* data) const;
+ ///Does not call the destructor, but frees all special data associated to \
dynamic data(the appendedlists stuff) + ///This needs to be called whenever a \
dynamic duchain data-pointer is being deleted. + void \
freeDynamicData(DUChainBaseData* data) const; +
/// Access the static DUChainItemSystem instance.
static DUChainItemSystem& self();
--- trunk/KDE/kdevplatform/language/duchain/ducontext.cpp #891017:891018
@@ -586,6 +586,8 @@
top->m_dynamicData->clearContextIndex(this);
}
+
+ Q_ASSERT(d_func()->isDynamic() == (!top->deleting() || !top->isOnDisk() || \
top->m_dynamicData->isTemporaryContextIndex(m_dynamicData->m_indexInTopContext))); }
QVector< DUContext * > DUContext::childContexts( ) const
--- trunk/KDE/kdevplatform/language/duchain/topducontext.cpp #891017:891018
@@ -802,7 +802,6 @@
DUCHAIN_D_DYNAMIC(TopDUContext);
d->m_features = VisibleDeclarationsAndContexts;
- d->m_deleting = false;
d->m_ownIndex = m_local->m_ownIndex;
m_local->m_file = ParsingEnvironmentFilePointer(file);
setInSymbolTable(true);
@@ -823,7 +822,7 @@
TopDUContext::~TopDUContext( )
{
if(!m_local->m_sharedDataOwner) {
- d_func_dynamic()->m_deleting = true;
+ m_dynamicData->m_deleting = true;
if(!isOnDisk())
clearUsedDeclarationIndices();
}
@@ -835,7 +834,7 @@
TopDUContextDynamicData* dynamicData = m_dynamicData;
if(!m_local->m_sharedDataOwner)
- d_func_dynamic()->m_deleting = true;
+ m_dynamicData->m_deleting = true;
delete this;
@@ -1225,7 +1224,8 @@
bool TopDUContext::deleting() const
{
- return d_func()->m_deleting;
+ ///@todo remove d_func()->m_deleting, not used any more
+ return m_dynamicData->m_deleting;
}
QList<ProblemPointer> TopDUContext::problems() const
--- trunk/KDE/kdevplatform/language/duchain/topducontextdynamicdata.cpp \
#891017:891018 @@ -59,7 +59,7 @@
item.setData(&target);
}
-TopDUContextDynamicData::TopDUContextDynamicData(TopDUContext* topContext) : \
m_topContext(topContext), m_fastContexts(0), m_fastContextsSize(0), \
m_fastDeclarations(0), m_fastDeclarationsSize(0), m_onDisk(false), m_dataLoaded(true) \
{ +TopDUContextDynamicData::TopDUContextDynamicData(TopDUContext* topContext) : \
m_topContext(topContext), m_fastContexts(0), m_fastContextsSize(0), \
m_fastDeclarations(0), m_fastDeclarationsSize(0), m_onDisk(false), \
m_dataLoaded(true), m_deleting(false) { }
TopDUContextDynamicData::~TopDUContextDynamicData() {
@@ -473,6 +473,14 @@
}
}
+bool TopDUContextDynamicData::isTemporaryContextIndex(uint index) const {
+ return !(index < (0x0fffffff/2));
+}
+
+bool TopDUContextDynamicData::isTemporaryDeclarationIndex(uint index) const {
+ return !(index < (0x0fffffff/2));
+}
+
DUContext* TopDUContextDynamicData::getContextForIndex(uint index) const {
if(!m_dataLoaded)
--- trunk/KDE/kdevplatform/language/duchain/topducontextdynamicdata.h #891017:891018
@@ -86,6 +86,11 @@
static QList<IndexedDUContext> loadImports(uint topContextIndex);
+ bool isTemporaryContextIndex(uint index) const;
+ bool isTemporaryDeclarationIndex(uint index) const ;
+
+ bool m_deleting; ///Flag used during destruction
+
private:
void loadData() const;
--- trunk/KDE/kdevplatform/language/duchain/types/typesystemdata.h #891017:891018
@@ -85,6 +85,9 @@
/// Expensive
unsigned int hash() const;
+ void freeDynamicData() {
+ }
+
private:
AbstractTypeData& operator=(const AbstractTypeData&);
};
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic