GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/context/context.cpp Lines: 170 198 85.9 %
Date: 2021-05-22 Branches: 210 582 36.1 %

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
2149736
Context::Context() : d_pCNOpre(NULL), d_pCNOpost(NULL) {
28
  // Create new memory manager
29
2149736
  d_pCMM = new ContextMemoryManager();
30
31
  // Create initial Scope
32
2149736
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, 0));
33
2149736
}
34
35
36
4299472
Context::~Context() {
37
  // Delete all Scopes
38
2149736
  popto(0);
39
40
  // Delete the memory manager
41
2149736
  delete d_pCMM;
42
43
  // Clear ContextNotifyObj lists so there are no dangling pointers
44
  ContextNotifyObj* pCNO;
45
2149740
  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
2149740
  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
2149736
}
58
59
60
2609133
void Context::push() {
61
5218266
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "Push [to "
62
2609133
                   << getLevel() + 1 << "] { " << this << std::endl;
63
64
  // Create a new memory region
65
2609133
  d_pCMM->push();
66
67
  // Create a new top Scope
68
2609133
  d_scopeList.push_back(new(d_pCMM) Scope(this, d_pCMM, getLevel()+1));
69
2609133
}
70
71
72
2609133
void Context::pop() {
73
2609133
  Assert(getLevel() > 0) << "Cannot pop below level 0";
74
75
  // Notify the (pre-pop) ContextNotifyObj objects
76
2609133
  ContextNotifyObj* pCNO = d_pCNOpre;
77
2609149
  while(pCNO != NULL) {
78
    // pre-store the "next" pointer in case pCNO deletes itself on notify()
79
8
    ContextNotifyObj* next = pCNO->d_pCNOnext;
80
8
    pCNO->contextNotifyPop();
81
8
    pCNO = next;
82
  }
83
84
  // Grab the top Scope
85
2609133
  Scope* pScope = d_scopeList.back();
86
87
  // Restore the previous Scope
88
2609133
  d_scopeList.pop_back();
89
90
  // Restore all objects in the top Scope
91
2609133
  delete pScope;
92
93
  // Pop the memory region
94
2609133
  d_pCMM->pop();
95
96
  // Notify the (post-pop) ContextNotifyObj objects
97
2609133
  pCNO = d_pCNOpost;
98
81949525
  while(pCNO != NULL) {
99
    // pre-store the "next" pointer in case pCNO deletes itself on notify()
100
39670196
    ContextNotifyObj* next = pCNO->d_pCNOnext;
101
39670196
    pCNO->contextNotifyPop();
102
39670196
    pCNO = next;
103
  }
104
105
5218266
  Trace("pushpop") << std::string(2 * getLevel(), ' ') << "} Pop [to "
106
2609133
                   << getLevel() << "] " << this << std::endl;
107
2609133
}
108
109
110
2169998
void Context::popto(int toLevel) {
111
  // Pop scopes until there are none left or toLevel is reached
112
2169998
  if(toLevel < 0) toLevel = 0;
113
2190180
  while(toLevel < getLevel()) pop();
114
2169998
}
115
116
117
4
void Context::addNotifyObjPre(ContextNotifyObj* pCNO) {
118
  // Insert pCNO at *front* of list
119
4
  if(d_pCNOpre != NULL)
120
2
    d_pCNOpre->prev() = &(pCNO->next());
121
4
  pCNO->next() = d_pCNOpre;
122
4
  pCNO->prev() = &d_pCNOpre;
123
4
  d_pCNOpre = pCNO;
124
4
}
125
126
127
325403
void Context::addNotifyObjPost(ContextNotifyObj* pCNO) {
128
  // Insert pCNO at *front* of list
129
325403
  if(d_pCNOpost != NULL)
130
243920
    d_pCNOpost->prev() = &(pCNO->next());
131
325403
  pCNO->next() = d_pCNOpost;
132
325403
  pCNO->prev() = &d_pCNOpost;
133
325403
  d_pCNOpost = pCNO;
134
325403
}
135
136
83498628
void ContextObj::update()
137
{
138
166997256
  Debug("context") << "before update(" << this << "):" << std::endl
139
166997256
                   << "context is " << getContext() << std::endl
140
83498628
                   << *getContext() << std::endl;
141
142
  // Call save() to save the information in the current object
143
83498628
  ContextObj* pContextObjSaved = save(d_pScope->getCMM());
144
145
166997256
  Debug("context") << "in update(" << this << ") with restore "
146
83498628
                   << pContextObjSaved << ": waypoint 1" << std::endl
147
83498628
                   << *getContext() << std::endl;
148
149
  // Check that base class data was saved
150
83498628
  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
166997256
  Debug("context") << "in update(" << this
159
83498628
                   << "): next() == " << next() << std::endl;
160
83498628
  if(next() != NULL) {
161
162749286
    Debug("context") << "in update(" << this
162
81374643
                     << "): next()->prev() == " << next()->prev() << std::endl;
163
81374643
    next()->prev() = &pContextObjSaved->next();
164
162749286
    Debug("context") << "in update(" << this
165
81374643
                     << "): next()->prev() is now "
166
81374643
                     << next()->prev() << std::endl;
167
  }
168
166997256
  Debug("context") << "in update(" << this
169
83498628
                   << "): prev() == " << prev() << std::endl;
170
166997256
  Debug("context") << "in update(" << this
171
83498628
                   << "): *prev() == " << *prev() << std::endl;
172
83498628
  *prev() = pContextObjSaved;
173
166997256
  Debug("context") << "in update(" << this
174
83498628
                   << "): *prev() is now " << *prev() << std::endl;
175
176
166997256
  Debug("context") << "in update(" << this << ") with restore "
177
83498628
                   << pContextObjSaved << ": waypoint 3" << std::endl
178
83498628
                   << *getContext() << std::endl;
179
180
  // Update Scope pointer to current top Scope
181
83498628
  d_pScope = d_pScope->getContext()->getTopScope();
182
183
  // Store the saved copy in the restore pointer
184
83498628
  d_pContextObjRestore = pContextObjSaved;
185
186
  // Insert object into the list of objects that need to be restored when this
187
  // Scope is popped.
188
83498628
  d_pScope->addToChain(this);
189
190
166997256
  Debug("context") << "after update(" << this << ") with restore "
191
83498628
                   << pContextObjSaved << ":" << std::endl
192
83498628
                   << *getContext() << std::endl;
193
83498628
}
194
195
83498628
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
83498628
  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
83498628
    restore(d_pContextObjRestore);
216
217
    // Remember the next object in the list
218
83498628
    pContextObjNext = d_pContextObjNext;
219
220
    // Restore the base class data
221
83498628
    d_pScope = d_pContextObjRestore->d_pScope;
222
83498628
    next() = d_pContextObjRestore->d_pContextObjNext;
223
83498628
    prev() = d_pContextObjRestore->d_ppContextObjPrev;
224
83498628
    d_pContextObjRestore = d_pContextObjRestore->d_pContextObjRestore;
225
226
    // Re-link this ContextObj to the list in this scope
227
83498628
    if(next() != NULL) {
228
81373884
      next()->prev() = &next();
229
    }
230
83498628
    *prev() = this;
231
  }
232
233
  // Return the next object in the list
234
83498628
  return pContextObjNext;
235
}
236
237
67260604
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
67260604
  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
134521208
  Debug("context") << "before destroy " << this << " (level " << getLevel()
248
67260604
                   << "):" << 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
67366996
    if (next() != nullptr)
257
    {
258
62395952
      next()->prev() = prev();
259
    }
260
67313800
    *prev() = next();
261
67313800
    if (d_pContextObjRestore == nullptr)
262
    {
263
67260604
      break;
264
    }
265
106392
    Debug("context") << "in destroy " << this << ", restore object is "
266
53196
                     << d_pContextObjRestore << " at level "
267
106392
                     << d_pContextObjRestore->getLevel() << ":" << std::endl
268
53196
                     << *getContext() << std::endl;
269
53196
    restoreAndContinue();
270
  }
271
134521208
  Debug("context") << "after destroy " << this << ":" << std::endl
272
67260604
                   << *getContext() << std::endl;
273
67260604
}
274
275
276
7928698
ContextObj::ContextObj(Context* pContext) :
277
  d_pScope(NULL),
278
  d_pContextObjRestore(NULL),
279
  d_pContextObjNext(NULL),
280
7928698
  d_ppContextObjPrev(NULL) {
281
7928698
  Assert(pContext != NULL) << "NULL context pointer";
282
283
7928698
  Debug("context") << "create new ContextObj(" << this << " inCMM=false)" << std::endl;
284
7928698
  d_pScope = pContext->getBottomScope();
285
7928698
  d_pScope->addToChain(this);
286
7928698
}
287
288
289
59331906
ContextObj::ContextObj(bool allocatedInCMM, Context* pContext) :
290
  d_pScope(NULL),
291
  d_pContextObjRestore(NULL),
292
  d_pContextObjNext(NULL),
293
59331906
  d_ppContextObjPrev(NULL) {
294
59331906
  Assert(pContext != NULL) << "NULL context pointer";
295
296
59331906
  Debug("context") << "create new ContextObj(" << this << " inCMM=" << allocatedInCMM << ")" << std::endl;
297
59331906
  if(allocatedInCMM) {
298
    d_pScope = pContext->getTopScope();
299
  } else {
300
59331906
    d_pScope = pContext->getBottomScope();
301
  }
302
59331906
  d_pScope->addToChain(this);
303
59331906
}
304
305
47664639
void ContextObj::enqueueToGarbageCollect() {
306
47664639
  Assert(d_pScope != NULL);
307
47664639
  d_pScope->enqueueToGarbageCollect(this);
308
47664639
}
309
310
325407
ContextNotifyObj::ContextNotifyObj(Context* pContext, bool preNotify) {
311
325407
  if(preNotify) {
312
4
    pContext->addNotifyObjPre(this);
313
  } else {
314
325403
    pContext->addNotifyObjPost(this);
315
  }
316
325407
}
317
318
319
650814
ContextNotifyObj::~ContextNotifyObj() {
320
325407
  if(d_pCNOnext != NULL) {
321
190304
    d_pCNOnext->d_ppCNOprev = d_ppCNOprev;
322
  }
323
325407
  if(d_ppCNOprev != NULL) {
324
325403
    *d_ppCNOprev = d_pCNOnext;
325
  }
326
325407
}
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
88663698
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
169499997
  while (d_pContextObjList != NULL) {
370
83445432
    d_pContextObjList = d_pContextObjList->restoreAndContinue();
371
  }
372
373
2609133
  if (d_garbage) {
374
97053009
    while (!d_garbage->empty()) {
375
47664639
      ContextObj* obj = d_garbage->back();
376
47664639
      d_garbage->pop_back();
377
47664639
      obj->deleteSelf();
378
    }
379
  }
380
2609133
}
381
382
47664639
void Scope::enqueueToGarbageCollect(ContextObj* obj) {
383
47664639
  if (!d_garbage) {
384
1723731
    d_garbage.reset(new std::vector<ContextObj*>);
385
  }
386
47664639
  d_garbage->push_back(obj);
387
47664639
}
388
389
}  // namespace context
390
28200
}  // namespace cvc5