GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/context/context.cpp Lines: 171 198 86.4 %
Date: 2021-08-06 Branches: 211 582 36.3 %

Line Exec Source
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-2021 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 {
24
namespace context {
25
26
27
1886198
Context::Context() : d_pCNOpre(NULL), d_pCNOpost(NULL) {
28
  // Create new memory manager
29
1886198
  d_pCMM = new ContextMemoryManager();
30
31
  // Create initial Scope
32
1886198
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, 0));
33
1886198
}
34
35
36
3772396
Context::~Context() {
37
  // Delete all Scopes
38
1886198
  popto(0);
39
40
  // Delete the memory manager
41
1886198
  delete d_pCMM;
42
43
  // Clear ContextNotifyObj lists so there are no dangling pointers
44
  ContextNotifyObj* pCNO;
45
1886202
  while(d_pCNOpre != NULL) {
46
2
    pCNO = d_pCNOpre;
47
2
    pCNO->d_ppCNOprev = NULL;
48
2
    d_pCNOpre = pCNO->d_pCNOnext;
49
2
    pCNO->d_pCNOnext = NULL;
50
  }
51
1886202
  while(d_pCNOpost != NULL) {
52
2
    pCNO = d_pCNOpost;
53
2
    pCNO->d_ppCNOprev = NULL;
54
2
    d_pCNOpost = pCNO->d_pCNOnext;
55
2
    pCNO->d_pCNOnext = NULL;
56
  }
57
1886198
}
58
59
60
3457392
void Context::push() {
61
6914784
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "Push [to "
62
3457392
                   << getLevel() + 1 << "] { " << this << std::endl;
63
64
  // Create a new memory region
65
3457392
  d_pCMM->push();
66
67
  // Create a new top Scope
68
3457392
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, getLevel()+1));
69
3457392
}
70
71
72
3457392
void Context::pop() {
73
3457392
  Assert(getLevel() > 0) << "Cannot pop below level 0";
74
75
  // Notify the (pre-pop) ContextNotifyObj objects
76
3457392
  ContextNotifyObj* pCNO = d_pCNOpre;
77
3457420
  while(pCNO != NULL) {
78
    // pre-store the "next" pointer in case pCNO deletes itself on notify()
79
14
    ContextNotifyObj* next = pCNO->d_pCNOnext;
80
14
    pCNO->contextNotifyPop();
81
14
    pCNO = next;
82
  }
83
84
  // Grab the top Scope
85
3457392
  Scope* pScope = d_scopeList.back();
86
87
  // Restore the previous Scope
88
3457392
  d_scopeList.pop_back();
89
90
  // Restore all objects in the top Scope
91
3457392
  delete pScope;
92
93
  // Pop the memory region
94
3457392
  d_pCMM->pop();
95
96
  // Notify the (post-pop) ContextNotifyObj objects
97
3457392
  pCNO = d_pCNOpost;
98
99369700
  while(pCNO != NULL) {
99
    // pre-store the "next" pointer in case pCNO deletes itself on notify()
100
47956154
    ContextNotifyObj* next = pCNO->d_pCNOnext;
101
47956154
    pCNO->contextNotifyPop();
102
47956154
    pCNO = next;
103
  }
104
105
6914784
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "} Pop [to "
106
3457392
                   << getLevel() << "] " << this << std::endl;
107
3457392
}
108
109
110
1907332
void Context::popto(int toLevel) {
111
  // Pop scopes until there are none left or toLevel is reached
112
1907332
  if(toLevel < 0) toLevel = 0;
113
1928378
  while(toLevel < getLevel()) pop();
114
1907332
}
115
116
117
8
void Context::addNotifyObjPre(ContextNotifyObj* pCNO) {
118
  // Insert pCNO at *front* of list
119
8
  if(d_pCNOpre != NULL)
120
2
    d_pCNOpre->prev() = &(pCNO->next());
121
8
  pCNO->next() = d_pCNOpre;
122
8
  pCNO->prev() = &d_pCNOpre;
123
8
  d_pCNOpre = pCNO;
124
8
}
125
126
127
328714
void Context::addNotifyObjPost(ContextNotifyObj* pCNO) {
128
  // Insert pCNO at *front* of list
129
328714
  if(d_pCNOpost != NULL)
130
240999
    d_pCNOpost->prev() = &(pCNO->next());
131
328714
  pCNO->next() = d_pCNOpost;
132
328714
  pCNO->prev() = &d_pCNOpost;
133
328714
  d_pCNOpost = pCNO;
134
328714
}
135
136
114644401
void ContextObj::update()
137
{
138
229288802
  Debug("context") << "before update(" << this << "):" << std::endl
139
229288802
                   << "context is " << getContext() << std::endl
140
114644401
                   << *getContext() << std::endl;
141
142
  // Call save() to save the information in the current object
143
114644401
  ContextObj* pContextObjSaved = save(d_pScope->getCMM());
144
145
229288802
  Debug("context") << "in update(" << this << ") with restore "
146
114644401
                   << pContextObjSaved << ": waypoint 1" << std::endl
147
114644401
                   << *getContext() << std::endl;
148
149
  // Check that base class data was saved
150
114644401
  Assert((pContextObjSaved->d_pContextObjNext == d_pContextObjNext
151
          && pContextObjSaved->d_ppContextObjPrev == d_ppContextObjPrev
152
          && pContextObjSaved->d_pContextObjRestore == d_pContextObjRestore
153
          && pContextObjSaved->d_pScope == d_pScope))
154
      << "save() did not properly copy information in base class";
155
156
  // Link the "saved" object in place of this ContextObj in the scope
157
  // we're moving it FROM.
158
229288802
  Debug("context") << "in update(" << this
159
114644401
                   << "): next() == " << next() << std::endl;
160
114644401
  if(next() != NULL) {
161
223544648
    Debug("context") << "in update(" << this
162
111772324
                     << "): next()->prev() == " << next()->prev() << std::endl;
163
111772324
    next()->prev() = &pContextObjSaved->next();
164
223544648
    Debug("context") << "in update(" << this
165
111772324
                     << "): next()->prev() is now "
166
111772324
                     << next()->prev() << std::endl;
167
  }
168
229288802
  Debug("context") << "in update(" << this
169
114644401
                   << "): prev() == " << prev() << std::endl;
170
229288802
  Debug("context") << "in update(" << this
171
114644401
                   << "): *prev() == " << *prev() << std::endl;
172
114644401
  *prev() = pContextObjSaved;
173
229288802
  Debug("context") << "in update(" << this
174
114644401
                   << "): *prev() is now " << *prev() << std::endl;
175
176
229288802
  Debug("context") << "in update(" << this << ") with restore "
177
114644401
                   << pContextObjSaved << ": waypoint 3" << std::endl
178
114644401
                   << *getContext() << std::endl;
179
180
  // Update Scope pointer to current top Scope
181
114644401
  d_pScope = d_pScope->getContext()->getTopScope();
182
183
  // Store the saved copy in the restore pointer
184
114644401
  d_pContextObjRestore = pContextObjSaved;
185
186
  // Insert object into the list of objects that need to be restored when this
187
  // Scope is popped.
188
114644401
  d_pScope->addToChain(this);
189
190
229288802
  Debug("context") << "after update(" << this << ") with restore "
191
114644401
                   << pContextObjSaved << ":" << std::endl
192
114644401
                   << *getContext() << std::endl;
193
114644401
}
194
195
114644401
ContextObj* ContextObj::restoreAndContinue()
196
{
197
  // Variable to hold next object in list
198
  ContextObj* pContextObjNext;
199
200
  // Check the restore pointer.  If NULL, this must be the bottom Scope
201
114644401
  if(d_pContextObjRestore == NULL) {
202
    // might not be bottom scope, since objects allocated in context
203
    // memory don't get linked to scope 0
204
    //
205
    // Assert(d_pScope == d_pScope->getContext()->getBottomScope()) <<
206
    //        "Expected bottom scope";
207
208
    Debug("context") << "NULL restore object! " << this << std::endl;
209
    pContextObjNext = d_pContextObjNext;
210
    d_pScope = nullptr;
211
212
    // Nothing else to do
213
  } else {
214
    // Call restore to update the subclass data
215
114644401
    restore(d_pContextObjRestore);
216
217
    // Remember the next object in the list
218
114644401
    pContextObjNext = d_pContextObjNext;
219
220
    // Restore the base class data
221
114644401
    d_pScope = d_pContextObjRestore->d_pScope;
222
114644401
    next() = d_pContextObjRestore->d_pContextObjNext;
223
114644401
    prev() = d_pContextObjRestore->d_ppContextObjPrev;
224
114644401
    d_pContextObjRestore = d_pContextObjRestore->d_pContextObjRestore;
225
226
    // Re-link this ContextObj to the list in this scope
227
114644401
    if(next() != NULL) {
228
111771544
      next()->prev() = &next();
229
    }
230
114644401
    *prev() = this;
231
  }
232
233
  // Return the next object in the list
234
114644401
  return pContextObjNext;
235
}
236
237
77369543
void ContextObj::destroy()
238
{
239
  /* The object to destroy must be valid, i.e., its current state must belong
240
   * to a scope. We remove the object and its previous versions from their
241
   * respective scopes below. If this assertion is failing, you may have
242
   * created an object at a non-zero level and let it outlive the destruction
243
   * of that level. */
244
77369543
  Assert(d_pScope != nullptr);
245
  /* Context can be big and complicated, so we only want to process this output
246
   * if we're really going to use it. (Same goes below.) */
247
154739086
  Debug("context") << "before destroy " << this << " (level " << getLevel()
248
77369543
                   << "):" << std::endl << *getContext() << std::endl;
249
250
  for (;;)
251
  {
252
    // If valgrind reports invalid writes on the next few lines,
253
    // here's a hint: make sure all classes derived from ContextObj in
254
    // the system properly call destroy() in their destructors.
255
    // That's needed to maintain this linked list properly.
256
77769399
    if (next() != nullptr)
257
    {
258
73014778
      next()->prev() = prev();
259
    }
260
77569471
    *prev() = next();
261
77569471
    if (d_pContextObjRestore == nullptr)
262
    {
263
77369543
      break;
264
    }
265
399856
    Debug("context") << "in destroy " << this << ", restore object is "
266
199928
                     << d_pContextObjRestore << " at level "
267
399856
                     << d_pContextObjRestore->getLevel() << ":" << std::endl
268
199928
                     << *getContext() << std::endl;
269
199928
    restoreAndContinue();
270
  }
271
154739086
  Debug("context") << "after destroy " << this << ":" << std::endl
272
77369543
                   << *getContext() << std::endl;
273
77369543
}
274
275
276
8204553
ContextObj::ContextObj(Context* pContext) :
277
  d_pScope(NULL),
278
  d_pContextObjRestore(NULL),
279
  d_pContextObjNext(NULL),
280
8204553
  d_ppContextObjPrev(NULL) {
281
8204553
  Assert(pContext != NULL) << "NULL context pointer";
282
283
8204553
  Debug("context") << "create new ContextObj(" << this << " inCMM=false)" << std::endl;
284
8204553
  d_pScope = pContext->getBottomScope();
285
8204553
  d_pScope->addToChain(this);
286
8204553
}
287
288
289
69164990
ContextObj::ContextObj(bool allocatedInCMM, Context* pContext) :
290
  d_pScope(NULL),
291
  d_pContextObjRestore(NULL),
292
  d_pContextObjNext(NULL),
293
69164990
  d_ppContextObjPrev(NULL) {
294
69164990
  Assert(pContext != NULL) << "NULL context pointer";
295
296
69164990
  Debug("context") << "create new ContextObj(" << this << " inCMM=" << allocatedInCMM << ")" << std::endl;
297
69164990
  if(allocatedInCMM) {
298
2
    d_pScope = pContext->getTopScope();
299
  } else {
300
69164988
    d_pScope = pContext->getBottomScope();
301
  }
302
69164990
  d_pScope->addToChain(this);
303
69164990
}
304
305
56540551
void ContextObj::enqueueToGarbageCollect() {
306
56540551
  Assert(d_pScope != NULL);
307
56540551
  d_pScope->enqueueToGarbageCollect(this);
308
56540551
}
309
310
328722
ContextNotifyObj::ContextNotifyObj(Context* pContext, bool preNotify) {
311
328722
  if(preNotify) {
312
8
    pContext->addNotifyObjPre(this);
313
  } else {
314
328714
    pContext->addNotifyObjPost(this);
315
  }
316
328722
}
317
318
319
657444
ContextNotifyObj::~ContextNotifyObj() {
320
328722
  if(d_pCNOnext != NULL) {
321
204671
    d_pCNOnext->d_ppCNOprev = d_ppCNOprev;
322
  }
323
328722
  if(d_ppCNOprev != NULL) {
324
328718
    *d_ppCNOprev = d_pCNOnext;
325
  }
326
328722
}
327
328
std::ostream& operator<<(std::ostream& out, const Context& context)
329
{
330
  static const std::string separator(79, '-');
331
332
  int level = context.d_scopeList.size() - 1;
333
  typedef std::vector<Scope*>::const_reverse_iterator const_reverse_iterator;
334
  for(const_reverse_iterator i = context.d_scopeList.rbegin();
335
      i != context.d_scopeList.rend();
336
      ++i, --level) {
337
    Scope* pScope = *i;
338
    Assert(pScope->getLevel() == level);
339
    Assert(pScope->getContext() == &context);
340
    out << separator << std::endl
341
        << *pScope << std::endl;
342
  }
343
  return out << separator << std::endl;
344
}
345
346
std::ostream& operator<<(std::ostream& out, const Scope& scope)
347
{
348
  out << "Scope " << scope.d_level << " [" << &scope << "]:";
349
  ContextObj* pContextObj = scope.d_pContextObjList;
350
  Assert(pContextObj == NULL
351
         || pContextObj->prev() == &scope.d_pContextObjList);
352
  while(pContextObj != NULL) {
353
    out << " <--> " << pContextObj;
354
    if(pContextObj->d_pScope != &scope) {
355
      out << " XXX bad scope" << std::endl;
356
    }
357
    Assert(pContextObj->d_pScope == &scope);
358
    Assert(pContextObj->next() == NULL
359
           || pContextObj->next()->prev() == &pContextObj->next());
360
    pContextObj = pContextObj->next();
361
  }
362
  return out << " --> NULL";
363
}
364
365
121359257
Scope::~Scope() {
366
  // Call restore() method on each ContextObj object in the list.
367
  // Note that it is the responsibility of restore() to return the
368
  // next item in the list.
369
232346338
  while (d_pContextObjList != NULL) {
370
114444473
    d_pContextObjList = d_pContextObjList->restoreAndContinue();
371
  }
372
373
3457392
  if (d_garbage) {
374
115256871
    while (!d_garbage->empty()) {
375
56540551
      ContextObj* obj = d_garbage->back();
376
56540551
      d_garbage->pop_back();
377
56540551
      obj->deleteSelf();
378
    }
379
  }
380
3457392
}
381
382
56540551
void Scope::enqueueToGarbageCollect(ContextObj* obj) {
383
56540551
  if (!d_garbage) {
384
2175769
    d_garbage.reset(new std::vector<ContextObj*>);
385
  }
386
56540551
  d_garbage->push_back(obj);
387
56540551
}
388
389
}  // namespace context
390
29328
}  // namespace cvc5