GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/context/context.cpp Lines: 171 198 86.4 %
Date: 2021-09-07 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
1930369
Context::Context() : d_pCNOpre(NULL), d_pCNOpost(NULL) {
28
  // Create new memory manager
29
1930369
  d_pCMM = new ContextMemoryManager();
30
31
  // Create initial Scope
32
1930369
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, 0));
33
1930369
}
34
35
36
3828962
Context::~Context() {
37
  // Delete all Scopes
38
1914481
  popto(0);
39
40
  // Delete the memory manager
41
1914481
  delete d_pCMM;
42
43
  // Clear ContextNotifyObj lists so there are no dangling pointers
44
  ContextNotifyObj* pCNO;
45
1914485
  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
1914485
  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
1914481
}
58
59
60
3475014
void Context::push() {
61
6950028
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "Push [to "
62
3475014
                   << getLevel() + 1 << "] { " << this << std::endl;
63
64
  // Create a new memory region
65
3475014
  d_pCMM->push();
66
67
  // Create a new top Scope
68
3475014
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, getLevel()+1));
69
3475014
}
70
71
72
3475005
void Context::pop() {
73
3475005
  Assert(getLevel() > 0) << "Cannot pop below level 0";
74
75
  // Notify the (pre-pop) ContextNotifyObj objects
76
3475005
  ContextNotifyObj* pCNO = d_pCNOpre;
77
3475033
  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
3475005
  Scope* pScope = d_scopeList.back();
86
87
  // Restore the previous Scope
88
3475005
  d_scopeList.pop_back();
89
90
  // Restore all objects in the top Scope
91
3475005
  delete pScope;
92
93
  // Pop the memory region
94
3475005
  d_pCMM->pop();
95
96
  // Notify the (post-pop) ContextNotifyObj objects
97
3475005
  pCNO = d_pCNOpost;
98
99667405
  while(pCNO != NULL) {
99
    // pre-store the "next" pointer in case pCNO deletes itself on notify()
100
48096200
    ContextNotifyObj* next = pCNO->d_pCNOnext;
101
48096200
    pCNO->contextNotifyPop();
102
48096200
    pCNO = next;
103
  }
104
105
6950010
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "} Pop [to "
106
3475005
                   << getLevel() << "] " << this << std::endl;
107
3475005
}
108
109
110
1935703
void Context::popto(int toLevel) {
111
  // Pop scopes until there are none left or toLevel is reached
112
1935703
  if(toLevel < 0) toLevel = 0;
113
1956887
  while(toLevel < getLevel()) pop();
114
1935703
}
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
337647
void Context::addNotifyObjPost(ContextNotifyObj* pCNO) {
128
  // Insert pCNO at *front* of list
129
337647
  if(d_pCNOpost != NULL)
130
247810
    d_pCNOpost->prev() = &(pCNO->next());
131
337647
  pCNO->next() = d_pCNOpost;
132
337647
  pCNO->prev() = &d_pCNOpost;
133
337647
  d_pCNOpost = pCNO;
134
337647
}
135
136
116921094
void ContextObj::update()
137
{
138
233842188
  Debug("context") << "before update(" << this << "):" << std::endl
139
233842188
                   << "context is " << getContext() << std::endl
140
116921094
                   << *getContext() << std::endl;
141
142
  // Call save() to save the information in the current object
143
116921094
  ContextObj* pContextObjSaved = save(d_pScope->getCMM());
144
145
233842188
  Debug("context") << "in update(" << this << ") with restore "
146
116921094
                   << pContextObjSaved << ": waypoint 1" << std::endl
147
116921094
                   << *getContext() << std::endl;
148
149
  // Check that base class data was saved
150
116921094
  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
233842188
  Debug("context") << "in update(" << this
159
116921094
                   << "): next() == " << next() << std::endl;
160
116921094
  if(next() != NULL) {
161
228051576
    Debug("context") << "in update(" << this
162
114025788
                     << "): next()->prev() == " << next()->prev() << std::endl;
163
114025788
    next()->prev() = &pContextObjSaved->next();
164
228051576
    Debug("context") << "in update(" << this
165
114025788
                     << "): next()->prev() is now "
166
114025788
                     << next()->prev() << std::endl;
167
  }
168
233842188
  Debug("context") << "in update(" << this
169
116921094
                   << "): prev() == " << prev() << std::endl;
170
233842188
  Debug("context") << "in update(" << this
171
116921094
                   << "): *prev() == " << *prev() << std::endl;
172
116921094
  *prev() = pContextObjSaved;
173
233842188
  Debug("context") << "in update(" << this
174
116921094
                   << "): *prev() is now " << *prev() << std::endl;
175
176
233842188
  Debug("context") << "in update(" << this << ") with restore "
177
116921094
                   << pContextObjSaved << ": waypoint 3" << std::endl
178
116921094
                   << *getContext() << std::endl;
179
180
  // Update Scope pointer to current top Scope
181
116921094
  d_pScope = d_pScope->getContext()->getTopScope();
182
183
  // Store the saved copy in the restore pointer
184
116921094
  d_pContextObjRestore = pContextObjSaved;
185
186
  // Insert object into the list of objects that need to be restored when this
187
  // Scope is popped.
188
116921094
  d_pScope->addToChain(this);
189
190
233842188
  Debug("context") << "after update(" << this << ") with restore "
191
116921094
                   << pContextObjSaved << ":" << std::endl
192
116921094
                   << *getContext() << std::endl;
193
116921094
}
194
195
116921085
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
116921085
  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
116921085
    restore(d_pContextObjRestore);
216
217
    // Remember the next object in the list
218
116921085
    pContextObjNext = d_pContextObjNext;
219
220
    // Restore the base class data
221
116921085
    d_pScope = d_pContextObjRestore->d_pScope;
222
116921085
    next() = d_pContextObjRestore->d_pContextObjNext;
223
116921085
    prev() = d_pContextObjRestore->d_ppContextObjPrev;
224
116921085
    d_pContextObjRestore = d_pContextObjRestore->d_pContextObjRestore;
225
226
    // Re-link this ContextObj to the list in this scope
227
116921085
    if(next() != NULL) {
228
114024999
      next()->prev() = &next();
229
    }
230
116921085
    *prev() = this;
231
  }
232
233
  // Return the next object in the list
234
116921085
  return pContextObjNext;
235
}
236
237
78072514
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
78072514
  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
156145028
  Debug("context") << "before destroy " << this << " (level " << getLevel()
248
78072514
                   << "):" << 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
78479686
    if (next() != nullptr)
257
    {
258
73758209
      next()->prev() = prev();
259
    }
260
78276100
    *prev() = next();
261
78276100
    if (d_pContextObjRestore == nullptr)
262
    {
263
78072514
      break;
264
    }
265
407172
    Debug("context") << "in destroy " << this << ", restore object is "
266
203586
                     << d_pContextObjRestore << " at level "
267
407172
                     << d_pContextObjRestore->getLevel() << ":" << std::endl
268
203586
                     << *getContext() << std::endl;
269
203586
    restoreAndContinue();
270
  }
271
156145028
  Debug("context") << "after destroy " << this << ":" << std::endl
272
78072514
                   << *getContext() << std::endl;
273
78072514
}
274
275
276
8333964
ContextObj::ContextObj(Context* pContext) :
277
  d_pScope(NULL),
278
  d_pContextObjRestore(NULL),
279
  d_pContextObjNext(NULL),
280
8333964
  d_ppContextObjPrev(NULL) {
281
8333964
  Assert(pContext != NULL) << "NULL context pointer";
282
283
8333964
  Debug("context") << "create new ContextObj(" << this << " inCMM=false)" << std::endl;
284
8333964
  d_pScope = pContext->getBottomScope();
285
8333964
  d_pScope->addToChain(this);
286
8333964
}
287
288
289
69766423
ContextObj::ContextObj(bool allocatedInCMM, Context* pContext) :
290
  d_pScope(NULL),
291
  d_pContextObjRestore(NULL),
292
  d_pContextObjNext(NULL),
293
69766423
  d_ppContextObjPrev(NULL) {
294
69766423
  Assert(pContext != NULL) << "NULL context pointer";
295
296
69766423
  Debug("context") << "create new ContextObj(" << this << " inCMM=" << allocatedInCMM << ")" << std::endl;
297
69766423
  if(allocatedInCMM) {
298
2
    d_pScope = pContext->getTopScope();
299
  } else {
300
69766421
    d_pScope = pContext->getBottomScope();
301
  }
302
69766423
  d_pScope->addToChain(this);
303
69766423
}
304
305
57658397
void ContextObj::enqueueToGarbageCollect() {
306
57658397
  Assert(d_pScope != NULL);
307
57658397
  d_pScope->enqueueToGarbageCollect(this);
308
57658397
}
309
310
337655
ContextNotifyObj::ContextNotifyObj(Context* pContext, bool preNotify) {
311
337655
  if(preNotify) {
312
8
    pContext->addNotifyObjPre(this);
313
  } else {
314
337647
    pContext->addNotifyObjPost(this);
315
  }
316
337655
}
317
318
319
648772
ContextNotifyObj::~ContextNotifyObj() {
320
324386
  if(d_pCNOnext != NULL) {
321
205934
    d_pCNOnext->d_ppCNOprev = d_ppCNOprev;
322
  }
323
324386
  if(d_ppCNOprev != NULL) {
324
324382
    *d_ppCNOprev = d_pCNOnext;
325
  }
326
324386
}
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
123667509
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
236910003
  while (d_pContextObjList != NULL) {
370
116717499
    d_pContextObjList = d_pContextObjList->restoreAndContinue();
371
  }
372
373
3475005
  if (d_garbage) {
374
117524516
    while (!d_garbage->empty()) {
375
57658397
      ContextObj* obj = d_garbage->back();
376
57658397
      d_garbage->pop_back();
377
57658397
      obj->deleteSelf();
378
    }
379
  }
380
3475005
}
381
382
57658397
void Scope::enqueueToGarbageCollect(ContextObj* obj) {
383
57658397
  if (!d_garbage) {
384
2207722
    d_garbage.reset(new std::vector<ContextObj*>);
385
  }
386
57658397
  d_garbage->push_back(obj);
387
57658397
}
388
389
}  // namespace context
390
29505
}  // namespace cvc5