[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