LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/context - context.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 129 157 82.2 %
Date: 2026-02-11 19:37:54 Functions: 17 20 85.0 %
Branches: 55 98 56.1 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Clark Barrett, Morgan Deters, Tim King
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Implementation of base context operations.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <iostream>
      17                 :            : #include <string>
      18                 :            : #include <vector>
      19                 :            : 
      20                 :            : #include "base/check.h"
      21                 :            : #include "context/context.h"
      22                 :            : 
      23                 :            : namespace cvc5::context {
      24                 :            : 
      25                 :   15253700 : Context::Context() : d_pCNOpre(NULL), d_pCNOpost(NULL) {
      26                 :            :   // Create new memory manager
      27                 :   15253700 :   d_pCMM = new ContextMemoryManager();
      28                 :            : 
      29                 :            :   // Create initial Scope
      30                 :   15253700 :   d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, 0));
      31                 :   15253700 : }
      32                 :            : 
      33                 :            : 
      34                 :   15231600 : Context::~Context() {
      35                 :            :   // Delete all Scopes
      36                 :   15231600 :   popto(0);
      37                 :            : 
      38                 :            :   // Delete the memory manager
      39         [ +  - ]:   15231600 :   delete d_pCMM;
      40                 :            : 
      41                 :            :   // Clear ContextNotifyObj lists so there are no dangling pointers
      42                 :            :   ContextNotifyObj* pCNO;
      43         [ +  + ]:   15231600 :   while(d_pCNOpre != NULL) {
      44                 :          1 :     pCNO = d_pCNOpre;
      45                 :          1 :     pCNO->d_ppCNOprev = NULL;
      46                 :          1 :     d_pCNOpre = pCNO->d_pCNOnext;
      47                 :          1 :     pCNO->d_pCNOnext = NULL;
      48                 :            :   }
      49         [ +  + ]:   15231600 :   while(d_pCNOpost != NULL) {
      50                 :          1 :     pCNO = d_pCNOpost;
      51                 :          1 :     pCNO->d_ppCNOprev = NULL;
      52                 :          1 :     d_pCNOpost = pCNO->d_pCNOnext;
      53                 :          1 :     pCNO->d_pCNOnext = NULL;
      54                 :            :   }
      55                 :   15231600 : }
      56                 :            : 
      57                 :  114759000 : uint32_t Context::getLevel() const
      58                 :            : {
      59 [ -  + ][ -  + ]:  114759000 :   Assert(d_scopeList.size() > 0);
                 [ -  - ]
      60                 :  114759000 :   return d_scopeList.size() - 1;
      61                 :            : }
      62                 :            : 
      63                 :   19008400 : void Context::push() {
      64                 :   38016900 :   Trace("pushpop") << std::string(2 * getLevel(), ' ') << "Push [to "
      65         [ -  + ]:   19008400 :                    << getLevel() + 1 << "] { " << this << std::endl;
      66                 :            : 
      67                 :            :   // Create a new memory region
      68                 :   19008400 :   d_pCMM->push();
      69                 :            : 
      70                 :            :   // Create a new top Scope
      71                 :   19008400 :   d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, getLevel()+1));
      72                 :   19008400 : }
      73                 :            : 
      74                 :            : 
      75                 :   19007100 : void Context::pop() {
      76 [ -  + ][ -  + ]:   19007100 :   Assert(getLevel() > 0) << "Cannot pop below level 0";
                 [ -  - ]
      77                 :            : 
      78                 :            :   // Notify the (pre-pop) ContextNotifyObj objects
      79                 :   19007100 :   ContextNotifyObj* pCNO = d_pCNOpre;
      80         [ +  + ]:   19007100 :   while(pCNO != NULL) {
      81                 :            :     // pre-store the "next" pointer in case pCNO deletes itself on notify()
      82                 :          5 :     ContextNotifyObj* next = pCNO->d_pCNOnext;
      83                 :          5 :     pCNO->contextNotifyPop();
      84                 :          5 :     pCNO = next;
      85                 :            :   }
      86                 :            : 
      87                 :            :   // Grab the top Scope
      88                 :   19007100 :   Scope* pScope = d_scopeList.back();
      89                 :            : 
      90                 :            :   // Restore the previous Scope
      91                 :   19007100 :   d_scopeList.pop_back();
      92                 :            : 
      93                 :            :   // Restore all objects in the top Scope
      94         [ +  - ]:   19007100 :   delete pScope;
      95                 :            : 
      96                 :            :   // Pop the memory region
      97                 :   19007100 :   d_pCMM->pop();
      98                 :            : 
      99                 :            :   // Notify the (post-pop) ContextNotifyObj objects
     100                 :   19007100 :   pCNO = d_pCNOpost;
     101         [ +  + ]:  159058000 :   while(pCNO != NULL) {
     102                 :            :     // pre-store the "next" pointer in case pCNO deletes itself on notify()
     103                 :  140051000 :     ContextNotifyObj* next = pCNO->d_pCNOnext;
     104                 :  140051000 :     pCNO->contextNotifyPop();
     105                 :  140051000 :     pCNO = next;
     106                 :            :   }
     107                 :            : 
     108                 :   38014200 :   Trace("pushpop") << std::string(2 * getLevel(), ' ') << "} Pop [to "
     109         [ -  + ]:   19007100 :                    << getLevel() << "] " << this << std::endl;
     110                 :   19007100 : }
     111                 :            : 
     112                 :   16090600 : void Context::popto(uint32_t toLevel)
     113                 :            : {
     114                 :            :   // Pop scopes until there are none left or toLevel is reached
     115         [ +  + ]:   16090600 :   while (toLevel < getLevel()) pop();
     116                 :   15639400 : }
     117                 :            : 
     118                 :          3 : void Context::addNotifyObjPre(ContextNotifyObj* pCNO) {
     119                 :            :   // Insert pCNO at *front* of list
     120         [ +  + ]:          3 :   if(d_pCNOpre != NULL)
     121                 :          1 :     d_pCNOpre->prev() = &(pCNO->next());
     122                 :          3 :   pCNO->next() = d_pCNOpre;
     123                 :          3 :   pCNO->prev() = &d_pCNOpre;
     124                 :          3 :   d_pCNOpre = pCNO;
     125                 :          3 : }
     126                 :            : 
     127                 :            : 
     128                 :    1723380 : void Context::addNotifyObjPost(ContextNotifyObj* pCNO) {
     129                 :            :   // Insert pCNO at *front* of list
     130         [ +  + ]:    1723380 :   if(d_pCNOpost != NULL)
     131                 :    1408420 :     d_pCNOpost->prev() = &(pCNO->next());
     132                 :    1723380 :   pCNO->next() = d_pCNOpost;
     133                 :    1723380 :   pCNO->prev() = &d_pCNOpost;
     134                 :    1723380 :   d_pCNOpost = pCNO;
     135                 :    1723380 : }
     136                 :            : 
     137                 :  304782000 : void ContextObj::update()
     138                 :            : {
     139                 :            :   // Call save() to save the information in the current object
     140                 :  304782000 :   ContextObj* pContextObjSaved = save(d_pScope->getCMM());
     141                 :            : 
     142                 :            :   // Check that base class data was saved
     143 [ +  - ][ +  - ]:  609564000 :   Assert((pContextObjSaved->d_pContextObjNext == d_pContextObjNext
         [ +  - ][ +  - ]
         [ -  + ][ -  - ]
     144                 :            :           && pContextObjSaved->d_ppContextObjPrev == d_ppContextObjPrev
     145                 :            :           && pContextObjSaved->d_pContextObjRestore == d_pContextObjRestore
     146                 :            :           && pContextObjSaved->d_pScope == d_pScope))
     147                 :          0 :       << "save() did not properly copy information in base class";
     148                 :            : 
     149                 :            :   // Link the "saved" object in place of this ContextObj in the scope
     150                 :            :   // we're moving it FROM.
     151         [ +  + ]:  304782000 :   if(next() != NULL) {
     152                 :  297536000 :     next()->prev() = &pContextObjSaved->next();
     153                 :            :   }
     154                 :  304782000 :   *prev() = pContextObjSaved;
     155                 :            : 
     156                 :            :   // Update Scope pointer to current top Scope
     157                 :  304782000 :   d_pScope = d_pScope->getContext()->getTopScope();
     158                 :            : 
     159                 :            :   // Store the saved copy in the restore pointer
     160                 :  304782000 :   d_pContextObjRestore = pContextObjSaved;
     161                 :            : 
     162                 :            :   // Insert object into the list of objects that need to be restored when this
     163                 :            :   // Scope is popped.
     164                 :  304782000 :   d_pScope->addToChain(this);
     165                 :  304782000 : }
     166                 :            : 
     167                 :  304766000 : ContextObj* ContextObj::restoreAndContinue()
     168                 :            : {
     169                 :            :   // Variable to hold next object in list
     170                 :            :   ContextObj* pContextObjNext;
     171                 :            : 
     172                 :            :   // Check the restore pointer.  If NULL, this must be the bottom Scope
     173         [ -  + ]:  304766000 :   if(d_pContextObjRestore == NULL) {
     174                 :            :     // might not be bottom scope, since objects allocated in context
     175                 :            :     // memory don't get linked to scope 0
     176                 :            :     //
     177                 :            :     // Assert(d_pScope == d_pScope->getContext()->getBottomScope()) <<
     178                 :            :     //        "Expected bottom scope";
     179                 :            : 
     180         [ -  - ]:          0 :     Trace("context") << "NULL restore object! " << this << std::endl;
     181                 :          0 :     pContextObjNext = d_pContextObjNext;
     182                 :          0 :     d_pScope = nullptr;
     183                 :            : 
     184                 :            :     // Nothing else to do
     185                 :            :   } else {
     186                 :            :     // Call restore to update the subclass data
     187                 :  304766000 :     restore(d_pContextObjRestore);
     188                 :            : 
     189                 :            :     // Remember the next object in the list
     190                 :  304766000 :     pContextObjNext = d_pContextObjNext;
     191                 :            : 
     192                 :            :     // Restore the base class data
     193                 :  304766000 :     d_pScope = d_pContextObjRestore->d_pScope;
     194                 :  304766000 :     next() = d_pContextObjRestore->d_pContextObjNext;
     195                 :  304766000 :     prev() = d_pContextObjRestore->d_ppContextObjPrev;
     196                 :  304766000 :     d_pContextObjRestore = d_pContextObjRestore->d_pContextObjRestore;
     197                 :            : 
     198                 :            :     // Re-link this ContextObj to the list in this scope
     199         [ +  + ]:  304766000 :     if(next() != NULL) {
     200                 :  297519000 :       next()->prev() = &next();
     201                 :            :     }
     202                 :  304766000 :     *prev() = this;
     203                 :            :   }
     204                 :            : 
     205                 :            :   // Return the next object in the list
     206                 :  304766000 :   return pContextObjNext;
     207                 :            : }
     208                 :            : 
     209                 :  255174000 : void ContextObj::destroy()
     210                 :            : {
     211                 :            :   /* The object to destroy must be valid, i.e., its current state must belong
     212                 :            :    * to a scope. We remove the object and its previous versions from their
     213                 :            :    * respective scopes below. If this assertion is failing, you may have
     214                 :            :    * created an object at a non-zero level and let it outlive the destruction
     215                 :            :    * of that level. */
     216 [ -  + ][ -  + ]:  255174000 :   Assert(d_pScope != nullptr);
                 [ -  - ]
     217                 :            :   /* Context can be big and complicated, so we only want to process this output
     218                 :            :    * if we're really going to use it. (Same goes below.) */
     219         [ +  - ]:  510348000 :   Trace("context") << "before destroy " << this << " (level " << getLevel()
     220                 :  255174000 :                    << "):" << std::endl << *getContext() << std::endl;
     221                 :            : 
     222                 :            :   for (;;)
     223                 :            :   {
     224                 :            :     // If valgrind reports invalid writes on the next few lines,
     225                 :            :     // here's a hint: make sure all classes derived from ContextObj in
     226                 :            :     // the system properly call destroy() in their destructors.
     227                 :            :     // That's needed to maintain this linked list properly.
     228         [ +  + ]:  256453000 :     if (next() != nullptr)
     229                 :            :     {
     230                 :  232250000 :       next()->prev() = prev();
     231                 :            :     }
     232                 :  256453000 :     *prev() = next();
     233         [ +  + ]:  256453000 :     if (d_pContextObjRestore == nullptr)
     234                 :            :     {
     235                 :  255174000 :       break;
     236                 :            :     }
     237                 :    1278710 :     restoreAndContinue();
     238                 :            :   }
     239         [ +  - ]:  510348000 :   Trace("context") << "after destroy " << this << ":" << std::endl
     240                 :  255174000 :                    << *getContext() << std::endl;
     241                 :  255174000 : }
     242                 :            : 
     243                 :            : 
     244                 :  255444000 : ContextObj::ContextObj(Context* pContext) :
     245                 :            :   d_pScope(NULL),
     246                 :            :   d_pContextObjRestore(NULL),
     247                 :            :   d_pContextObjNext(NULL),
     248                 :  255444000 :   d_ppContextObjPrev(NULL) {
     249 [ -  + ][ -  + ]:  255444000 :   Assert(pContext != NULL) << "NULL context pointer";
                 [ -  - ]
     250                 :            : 
     251         [ +  - ]:  255444000 :   Trace("context") << "create new ContextObj(" << this << " inCMM=false)" << std::endl;
     252                 :  255444000 :   d_pScope = pContext->getBottomScope();
     253                 :  255444000 :   d_pScope->addToChain(this);
     254                 :  255444000 : }
     255                 :            : 
     256                 :  129271000 : void ContextObj::enqueueToGarbageCollect() {
     257 [ -  + ][ -  + ]:  129271000 :   Assert(d_pScope != NULL);
                 [ -  - ]
     258                 :  129271000 :   d_pScope->enqueueToGarbageCollect(this);
     259                 :  129271000 : }
     260                 :            : 
     261                 :    1723380 : ContextNotifyObj::ContextNotifyObj(Context* pContext, bool preNotify) {
     262         [ +  + ]:    1723380 :   if(preNotify) {
     263                 :          3 :     pContext->addNotifyObjPre(this);
     264                 :            :   } else {
     265                 :    1723380 :     pContext->addNotifyObjPost(this);
     266                 :            :   }
     267                 :    1723380 : }
     268                 :            : 
     269                 :            : 
     270                 :    3398340 : ContextNotifyObj::~ContextNotifyObj() {
     271         [ +  + ]:    1699170 :   if(d_pCNOnext != NULL) {
     272                 :    1197240 :     d_pCNOnext->d_ppCNOprev = d_ppCNOprev;
     273                 :            :   }
     274         [ +  + ]:    1699170 :   if(d_ppCNOprev != NULL) {
     275                 :    1699170 :     *d_ppCNOprev = d_pCNOnext;
     276                 :            :   }
     277                 :    1699170 : }
     278                 :            : 
     279                 :          0 : std::ostream& operator<<(std::ostream& out, const Context& context)
     280                 :            : {
     281                 :          0 :   static const std::string separator(79, '-');
     282                 :            : 
     283                 :          0 :   uint32_t level = context.d_scopeList.size() - 1;
     284                 :            :   typedef std::vector<Scope*>::const_reverse_iterator const_reverse_iterator;
     285                 :          0 :   for(const_reverse_iterator i = context.d_scopeList.rbegin();
     286         [ -  - ]:          0 :       i != context.d_scopeList.rend();
     287                 :          0 :       ++i, --level) {
     288                 :          0 :     Scope* pScope = *i;
     289                 :          0 :     Assert(pScope->getLevel() == level);
     290                 :          0 :     Assert(pScope->getContext() == &context);
     291                 :          0 :     out << separator << std::endl
     292                 :          0 :         << *pScope << std::endl;
     293                 :            :   }
     294                 :          0 :   return out << separator << std::endl;
     295                 :            : }
     296                 :            : 
     297                 :          0 : std::ostream& operator<<(std::ostream& out, const Scope& scope)
     298                 :            : {
     299                 :          0 :   out << "Scope " << scope.d_level << " [" << &scope << "]:";
     300                 :          0 :   ContextObj* pContextObj = scope.d_pContextObjList;
     301                 :          0 :   Assert(pContextObj == NULL
     302                 :            :          || pContextObj->prev() == &scope.d_pContextObjList);
     303         [ -  - ]:          0 :   while(pContextObj != NULL) {
     304                 :          0 :     out << " <--> " << pContextObj;
     305         [ -  - ]:          0 :     if(pContextObj->d_pScope != &scope) {
     306                 :          0 :       out << " XXX bad scope" << std::endl;
     307                 :            :     }
     308                 :          0 :     Assert(pContextObj->d_pScope == &scope);
     309                 :          0 :     Assert(pContextObj->next() == NULL
     310                 :            :            || pContextObj->next()->prev() == &pContextObj->next());
     311                 :          0 :     pContextObj = pContextObj->next();
     312                 :            :   }
     313                 :          0 :   return out << " --> NULL";
     314                 :            : }
     315                 :            : 
     316                 :   19007100 : Scope::~Scope() {
     317                 :            :   // Call restore() method on each ContextObj object in the list.
     318                 :            :   // Note that it is the responsibility of restore() to return the
     319                 :            :   // next item in the list.
     320         [ +  + ]:  322494000 :   while (d_pContextObjList != NULL) {
     321                 :  303487000 :     d_pContextObjList = d_pContextObjList->restoreAndContinue();
     322                 :            :   }
     323                 :            : 
     324         [ +  + ]:  148278000 :   for (ContextObj* obj : d_garbage)
     325                 :            :   {
     326                 :  129271000 :     obj->deleteSelf();
     327                 :            :   }
     328                 :   19007100 : }
     329                 :            : 
     330                 :  129271000 : void Scope::enqueueToGarbageCollect(ContextObj* obj) {
     331                 :  129271000 :   d_garbage.push_back(obj);
     332                 :  129271000 : }
     333                 :            : 
     334                 :            : }  // namespace cvc5::context

Generated by: LCOV version 1.14