[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