LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/context - context.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 131 159 82.4 %
Date: 2026-08-22 10:38:04 Functions: 17 20 85.0 %
Branches: 58 104 55.8 %

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

Generated by: LCOV version 1.14