1 /********************* */
3 ** Original author: mdeters
4 ** Major contributors: dejan
5 ** Minor contributors (to current version): none
6 ** This file is part of the CVC4 prototype.
7 ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys)
8 ** Courant Institute of Mathematical Sciences
10 ** See the file COPYING in the top-level source directory for licensing
13 ** Expression manager implementation.
16 #include "node_manager.h"
18 #include <ext/hash_set>
21 using namespace CVC4::expr
;
22 using __gnu_cxx::hash_set
;
26 __thread NodeManager
* NodeManager::s_current
= 0;
28 NodeManager::NodeManager(context::Context
* ctxt
) :
30 d_nodeUnderDeletion(NULL
),
32 poolInsert( &expr::NodeValue::s_null
);
34 for(unsigned i
= 0; i
< unsigned(kind::LAST_KIND
); ++i
) {
38 d_operators
[i
] = mkConst(Kind(k
));
43 NodeManager::~NodeManager() {
44 // have to ensure "this" is the current NodeManager during
45 // destruction of operators, because they get GCed.
47 NodeManagerScope
nms(this);
49 for(unsigned i
= 0; i
< unsigned(kind::LAST_KIND
); ++i
) {
50 d_operators
[i
] = Node::null();
53 while(!d_zombies
.empty()) {
57 poolRemove( &expr::NodeValue::s_null
);
61 * This class ensure that NodeManager::d_reclaiming gets set to false
62 * even on exceptional exit from NodeManager::reclaimZombies().
66 Reclaim(bool& reclaim
) :
67 d_reclaimField(reclaim
) {
69 Debug("gc") << ">> setting RECLAIM field\n";
70 d_reclaimField
= true;
73 Debug("gc") << "<< clearing RECLAIM field\n";
74 d_reclaimField
= false;
79 NodeValue
*& d_reclaimField
;
80 NVReclaim(NodeValue
*& reclaim
) :
81 d_reclaimField(reclaim
) {
83 Debug("gc") << ">> setting NVRECLAIM field\n";
86 Debug("gc") << "<< clearing NVRECLAIM field\n";
87 d_reclaimField
= NULL
;
91 void NodeManager::reclaimZombies() {
92 // FIXME multithreading
94 Debug("gc") << "reclaiming " << d_zombies
.size() << " zombie(s)!\n";
96 // during reclamation, reclaimZombies() is never supposed to be called
97 Assert(! d_reclaiming
, "NodeManager::reclaimZombies() not re-entrant!");
99 // whether exit is normal or exceptional, the Reclaim dtor is called
100 // and ensures that d_reclaiming is set back to false.
101 Reclaim
r(d_reclaiming
);
103 // We copy the set away and clear the NodeManager's set of zombies.
104 // This is because reclaimZombie() decrements the RC of the
105 // NodeValue's children, which may (recursively) reclaim them.
107 // Let's say we're reclaiming zombie NodeValue "A" and its child "B"
108 // then becomes a zombie (NodeManager::gc(B) is called).
110 // One way to handle B's zombification is simply to put it into
111 // d_zombies. This is what we do. However, if we're currently
112 // processing d_zombies in the loop below, such addition may be
113 // invisible to us (B is leaked) or even invalidate our iterator,
116 vector
<NodeValue
*> zombies
;
117 zombies
.reserve(d_zombies
.size());
118 std::copy(d_zombies
.begin(),
120 std::back_inserter(zombies
));
123 for(vector
<NodeValue
*>::iterator i
= zombies
.begin();
128 // collect ONLY IF still zero
130 Debug("gc") << "deleting node value " << nv
131 << " [" << nv
->d_id
<< "]: " << *nv
<< "\n";
133 // remove from the pool
134 if(nv
->getKind() != kind::VARIABLE
) {
138 // whether exit is normal or exceptional, the NVReclaim dtor is
139 // called and ensures that d_nodeUnderDeletion is set back to
141 NVReclaim
rc(d_nodeUnderDeletion
);
142 d_nodeUnderDeletion
= nv
;
145 d_attrManager
.deleteAllAttributes(nv
);
147 // decr ref counts of children
154 }/* CVC4 namespace */