1 /********************* */
2 /*! \file node_manager.cpp
4 ** Original author: mdeters
5 ** Major contributors: cconway
6 ** Minor contributors (to current version): acsys, taking, dejan
7 ** This file is part of the CVC4 prototype.
8 ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
9 ** Courant Institute of Mathematical Sciences
10 ** New York University
11 ** See the file COPYING in the top-level source directory for licensing
12 ** information.\endverbatim
14 ** \brief Expression manager implementation.
16 ** Expression manager implementation.
18 ** Reviewed by Chris Conway, Apr 5 2010 (bug #65).
21 #include "node_manager.h"
23 #include "theory/builtin/theory_builtin_type_rules.h"
24 #include "theory/booleans/theory_bool_type_rules.h"
25 #include "theory/uf/theory_uf_type_rules.h"
26 #include "theory/arith/theory_arith_type_rules.h"
27 #include "theory/arrays/theory_arrays_type_rules.h"
28 #include "theory/bv/theory_bv_type_rules.h"
29 #include "theory/datatypes/theory_datatypes_type_rules.h"
31 #include "util/Assert.h"
32 #include "util/options.h"
33 #include "util/stats.h"
38 #include <ext/hash_set>
41 using namespace CVC4::expr
;
42 using __gnu_cxx::hash_set
;
46 CVC4_THREADLOCAL(NodeManager
*) NodeManager::s_current
= NULL
;
49 * This class sets it reference argument to true and ensures that it gets set
50 * to false on destruction. This can be used to make sure a flag gets toggled
51 * in a function even on exceptional exit (e.g., see reclaimZombies()).
56 ScopedBool(bool& value
) :
59 Debug("gc") << ">> setting ScopedBool\n";
64 Debug("gc") << "<< clearing ScopedBool\n";
70 * Similarly, ensure d_nodeUnderDeletion gets set to NULL even on
71 * exceptional exit from NodeManager::reclaimZombies().
74 NodeValue
*& d_deletionField
;
76 NVReclaim(NodeValue
*& deletionField
) :
77 d_deletionField(deletionField
) {
79 Debug("gc") << ">> setting NVRECLAIM field\n";
83 Debug("gc") << "<< clearing NVRECLAIM field\n";
84 d_deletionField
= NULL
;
88 NodeManager::NodeManager(context::Context
* ctxt
,
89 ExprManager
* exprManager
) :
90 d_optionsAllocated(new Options()),
91 d_options(d_optionsAllocated
),
92 d_statisticsRegistry(new StatisticsRegistry()),
94 d_exprManager(exprManager
),
95 d_nodeUnderDeletion(NULL
),
96 d_inReclaimZombies(false) {
101 NodeManager::NodeManager(context::Context
* ctxt
,
102 ExprManager
* exprManager
,
103 const Options
& options
) :
104 d_optionsAllocated(NULL
),
106 d_statisticsRegistry(new StatisticsRegistry()),
108 d_exprManager(exprManager
),
109 d_nodeUnderDeletion(NULL
),
110 d_inReclaimZombies(false) {
114 inline void NodeManager::init() {
115 poolInsert( &expr::NodeValue::s_null
);
117 for(unsigned i
= 0; i
< unsigned(kind::LAST_KIND
); ++i
) {
121 d_operators
[i
] = mkConst(Kind(k
));
126 NodeManager::~NodeManager() {
127 // have to ensure "this" is the current NodeManager during
128 // destruction of operators, because they get GCed.
130 NodeManagerScope
nms(this);
133 ScopedBool
dontGC(d_inReclaimZombies
);
134 d_attrManager
.deleteAllAttributes();
137 for(unsigned i
= 0; i
< unsigned(kind::LAST_KIND
); ++i
) {
138 d_operators
[i
] = Node::null();
141 while(!d_zombies
.empty()) {
145 poolRemove( &expr::NodeValue::s_null
);
147 if(Debug
.isOn("gc:leaks")) {
148 Debug("gc:leaks") << "still in pool:" << std::endl
;
149 for(NodeValuePool::const_iterator i
= d_nodeValuePool
.begin(),
150 iend
= d_nodeValuePool
.end();
153 Debug("gc:leaks") << " " << *i
154 << " id=" << (*i
)->d_id
155 << " rc=" << (*i
)->d_rc
156 << " " << **i
<< std::endl
;
158 Debug("gc:leaks") << ":end:" << std::endl
;
161 delete d_statisticsRegistry
;
162 delete d_optionsAllocated
;
165 void NodeManager::reclaimZombies() {
166 // FIXME multithreading
168 Debug("gc") << "reclaiming " << d_zombies
.size() << " zombie(s)!\n";
170 // during reclamation, reclaimZombies() is never supposed to be called
171 Assert(! d_inReclaimZombies
, "NodeManager::reclaimZombies() not re-entrant!");
173 // whether exit is normal or exceptional, the Reclaim dtor is called
174 // and ensures that d_inReclaimZombies is set back to false.
175 ScopedBool
r(d_inReclaimZombies
);
177 // We copy the set away and clear the NodeManager's set of zombies.
178 // This is because reclaimZombie() decrements the RC of the
179 // NodeValue's children, which may (recursively) reclaim them.
181 // Let's say we're reclaiming zombie NodeValue "A" and its child "B"
182 // then becomes a zombie (NodeManager::markForDeletion(B) is called).
184 // One way to handle B's zombification would be simply to put it
185 // into d_zombies. This is what we do. However, if we were to
186 // concurrently process d_zombies in the loop below, such addition
187 // may be invisible to us (B is leaked) or even invalidate our
188 // iterator, causing a crash. So we need to copy the set away.
190 vector
<NodeValue
*> zombies
;
191 zombies
.reserve(d_zombies
.size());
192 std::remove_copy_if(d_zombies
.begin(),
194 std::back_inserter(zombies
),
195 NodeValueReferenceCountNonZero());
198 for(vector
<NodeValue
*>::iterator i
= zombies
.begin();
203 // collect ONLY IF still zero
205 if(Debug
.isOn("gc")) {
206 Debug("gc") << "deleting node value " << nv
207 << " [" << nv
->d_id
<< "]: ";
208 nv
->printAst(Debug("gc"));
209 Debug("gc") << std::endl
;
212 // remove from the pool
213 kind::MetaKind mk
= nv
->getMetaKind();
214 if(mk
!= kind::metakind::VARIABLE
) {
218 // whether exit is normal or exceptional, the NVReclaim dtor is
219 // called and ensures that d_nodeUnderDeletion is set back to
221 NVReclaim
rc(d_nodeUnderDeletion
);
222 d_nodeUnderDeletion
= nv
;
225 d_attrManager
.deleteAllAttributes(nv
);
227 // decr ref counts of children
229 if(mk
== kind::metakind::CONSTANT
) {
230 // Destroy (call the destructor for) the C++ type representing
231 // the constant in this NodeValue. This is needed for
232 // e.g. CVC4::Rational, since it has a gmp internal
233 // representation that mallocs memory and should be cleaned
234 // up. (This won't delete a pointer value if used as a
235 // constant, but then, you should probably use a smart-pointer
236 // type for a constant payload.)
237 kind::metakind::deleteNodeValueConstant(nv
);
242 }/* NodeManager::reclaimZombies() */
244 TypeNode
NodeManager::computeType(TNode n
, bool check
)
245 throw (TypeCheckingExceptionPrivate
, AssertionException
) {
249 switch(n
.getKind()) {
251 typeNode
= getAttribute(n
, TypeAttr());
254 typeNode
= getAttribute(n
, TypeAttr());
257 typeNode
= builtinOperatorType();
259 case kind::SORT_TYPE
:
260 typeNode
= kindType();
263 typeNode
= CVC4::theory::builtin::ApplyTypeRule::computeType(this, n
, check
);
266 typeNode
= CVC4::theory::builtin::EqualityTypeRule::computeType(this, n
, check
);
269 typeNode
= CVC4::theory::builtin::DistinctTypeRule::computeType(this, n
, check
);
272 typeNode
= CVC4::theory::builtin::TupleTypeRule::computeType(this, n
, check
);
274 case kind::CONST_BOOLEAN
:
275 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
278 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
281 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
284 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
287 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
290 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
293 typeNode
= CVC4::theory::boolean::BooleanTypeRule::computeType(this, n
, check
);
296 typeNode
= CVC4::theory::boolean::IteTypeRule::computeType(this, n
, check
);
299 typeNode
= CVC4::theory::uf::UfTypeRule::computeType(this, n
, check
);
302 typeNode
= CVC4::theory::arith::ArithOperatorTypeRule::computeType(this, n
, check
);
305 typeNode
= CVC4::theory::arith::ArithOperatorTypeRule::computeType(this, n
, check
);
308 typeNode
= CVC4::theory::arith::ArithOperatorTypeRule::computeType(this, n
, check
);
311 typeNode
= CVC4::theory::arith::ArithOperatorTypeRule::computeType(this, n
, check
);
314 typeNode
= CVC4::theory::arith::ArithOperatorTypeRule::computeType(this, n
, check
);
316 case kind::CONST_RATIONAL
:
317 typeNode
= CVC4::theory::arith::ArithConstantTypeRule::computeType(this, n
, check
);
319 case kind::CONST_INTEGER
:
320 typeNode
= CVC4::theory::arith::ArithConstantTypeRule::computeType(this, n
, check
);
323 typeNode
= CVC4::theory::arith::ArithPredicateTypeRule::computeType(this, n
, check
);
326 typeNode
= CVC4::theory::arith::ArithPredicateTypeRule::computeType(this, n
, check
);
329 typeNode
= CVC4::theory::arith::ArithPredicateTypeRule::computeType(this, n
, check
);
332 typeNode
= CVC4::theory::arith::ArithPredicateTypeRule::computeType(this, n
, check
);
335 typeNode
= CVC4::theory::arrays::ArraySelectTypeRule::computeType(this, n
, check
);
338 typeNode
= CVC4::theory::arrays::ArrayStoreTypeRule::computeType(this, n
, check
);
340 case kind::CONST_BITVECTOR
:
341 typeNode
= CVC4::theory::bv::BitVectorConstantTypeRule::computeType(this, n
, check
);
343 case kind::BITVECTOR_AND
:
344 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
346 case kind::BITVECTOR_OR
:
347 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
349 case kind::BITVECTOR_XOR
:
350 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
352 case kind::BITVECTOR_NOT
:
353 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
355 case kind::BITVECTOR_NAND
:
356 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
358 case kind::BITVECTOR_NOR
:
359 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
361 case kind::BITVECTOR_XNOR
:
362 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
364 case kind::BITVECTOR_COMP
:
365 typeNode
= CVC4::theory::bv::BitVectorCompRule::computeType(this, n
, check
);
367 case kind::BITVECTOR_MULT
:
368 typeNode
= CVC4::theory::bv::BitVectorArithRule::computeType(this, n
, check
);
370 case kind::BITVECTOR_PLUS
:
371 typeNode
= CVC4::theory::bv::BitVectorArithRule::computeType(this, n
, check
);
373 case kind::BITVECTOR_SUB
:
374 typeNode
= CVC4::theory::bv::BitVectorArithRule::computeType(this, n
, check
);
376 case kind::BITVECTOR_NEG
:
377 typeNode
= CVC4::theory::bv::BitVectorArithRule::computeType(this, n
, check
);
379 case kind::BITVECTOR_UDIV
:
380 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
382 case kind::BITVECTOR_UREM
:
383 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
385 case kind::BITVECTOR_SDIV
:
386 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
388 case kind::BITVECTOR_SREM
:
389 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
391 case kind::BITVECTOR_SMOD
:
392 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
394 case kind::BITVECTOR_SHL
:
395 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
397 case kind::BITVECTOR_LSHR
:
398 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
400 case kind::BITVECTOR_ASHR
:
401 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
403 case kind::BITVECTOR_ROTATE_LEFT
:
404 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
406 case kind::BITVECTOR_ROTATE_RIGHT
:
407 typeNode
= CVC4::theory::bv::BitVectorFixedWidthTypeRule::computeType(this, n
, check
);
409 case kind::BITVECTOR_ULT
:
410 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
412 case kind::BITVECTOR_ULE
:
413 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
415 case kind::BITVECTOR_UGT
:
416 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
418 case kind::BITVECTOR_UGE
:
419 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
421 case kind::BITVECTOR_SLT
:
422 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
424 case kind::BITVECTOR_SLE
:
425 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
427 case kind::BITVECTOR_SGT
:
428 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
430 case kind::BITVECTOR_SGE
:
431 typeNode
= CVC4::theory::bv::BitVectorPredicateTypeRule::computeType(this, n
, check
);
433 case kind::BITVECTOR_EXTRACT
:
434 typeNode
= CVC4::theory::bv::BitVectorExtractTypeRule::computeType(this, n
, check
);
436 case kind::BITVECTOR_CONCAT
:
437 typeNode
= CVC4::theory::bv::BitVectorConcatRule::computeType(this, n
, check
);
439 case kind::BITVECTOR_REPEAT
:
440 typeNode
= CVC4::theory::bv::BitVectorRepeatTypeRule::computeType(this, n
, check
);
442 case kind::BITVECTOR_ZERO_EXTEND
:
443 typeNode
= CVC4::theory::bv::BitVectorExtendTypeRule::computeType(this, n
, check
);
445 case kind::BITVECTOR_SIGN_EXTEND
:
446 typeNode
= CVC4::theory::bv::BitVectorExtendTypeRule::computeType(this, n
, check
);
448 case kind::APPLY_CONSTRUCTOR
:
449 typeNode
= CVC4::theory::datatypes::DatatypeConstructorTypeRule::computeType(this, n
, check
);
451 case kind::APPLY_SELECTOR
:
452 typeNode
= CVC4::theory::datatypes::DatatypeSelectorTypeRule::computeType(this, n
, check
);
454 case kind::APPLY_TESTER
:
455 typeNode
= CVC4::theory::datatypes::DatatypeTesterTypeRule::computeType(this, n
, check
);
457 case kind::APPLY_TYPE_ASCRIPTION
:
458 typeNode
= CVC4::theory::datatypes::DatatypeAscriptionTypeRule::computeType(this, n
, check
);
461 Debug("getType") << "FAILURE" << std::endl
;
462 Unhandled(n
.getKind());
465 setAttribute(n
, TypeAttr(), typeNode
);
466 setAttribute(n
, TypeCheckedAttr(),
467 check
|| getAttribute(n
, TypeCheckedAttr()));
472 TypeNode
NodeManager::getType(TNode n
, bool check
)
473 throw (TypeCheckingExceptionPrivate
, AssertionException
) {
474 // Many theories' type checkers call Node::getType() directly.
475 // This is incorrect, since "this" might not be the caller's
476 // curent node manager. Rather than force the individual typecheckers
477 // not to do this (by policy, which would be imperfect and lead
478 // to hard-to-find bugs, which it has in the past), we just
479 // set this node manager to be current for the duration of this
481 NodeManagerScope
nms(this);
484 bool hasType
= getAttribute(n
, TypeAttr(), typeNode
);
485 bool needsCheck
= check
&& !getAttribute(n
, TypeCheckedAttr());
487 Debug("getType") << "getting type for " << n
<< std::endl
;
489 if(needsCheck
&& !d_options
->earlyTypeChecking
) {
490 /* Iterate and compute the children bottom up. This avoids stack
491 overflows in computeType() when the Node graph is really deep,
492 which should only affect us when we're type checking lazily. */
493 stack
<TNode
> worklist
;
496 while( !worklist
.empty() ) {
497 TNode m
= worklist
.top();
499 bool readyToCompute
= true;
501 for( TNode::iterator it
= m
.begin(), end
= m
.end();
504 if( !hasAttribute(*it
, TypeAttr())
505 || (check
&& !getAttribute(*it
, TypeCheckedAttr())) ) {
506 readyToCompute
= false;
511 if( readyToCompute
) {
512 /* All the children have types, time to compute */
513 typeNode
= computeType(m
, check
);
518 /* Last type computed in loop should be the type of n */
519 Assert( typeNode
== getAttribute(n
, TypeAttr()) );
520 } else if( !hasType
|| needsCheck
) {
521 /* We can compute the type top-down, without worrying about
523 typeNode
= computeType(n
, check
);
526 /* The type should be have been computed and stored. */
527 Assert( hasAttribute(n
, TypeAttr()) );
528 /* The check should have happened, if we asked for it. */
529 Assert( !check
|| getAttribute(n
, TypeCheckedAttr()) );
531 Debug("getType") << "type of " << n
<< " is " << typeNode
<< std::endl
;
535 TypeNode
NodeManager::mkConstructorType(const Datatype::Constructor
& constructor
,
537 std::vector
<TypeNode
> sorts
;
538 Debug("datatypes") << "ctor name: " << constructor
.getName() << std::endl
;
539 for(Datatype::Constructor::const_iterator i
= constructor
.begin();
540 i
!= constructor
.end();
542 TypeNode selectorType
= *(*i
).getSelector().getType().d_typeNode
;
543 Debug("datatypes") << selectorType
<< std::endl
;
544 TypeNode sort
= selectorType
[1];
546 // should be guaranteed here already, but just in case
547 Assert(!sort
.isFunctionLike());
549 Debug("datatypes") << "ctor sort: " << sort
<< std::endl
;
550 sorts
.push_back(sort
);
552 Debug("datatypes") << "ctor range: " << range
<< std::endl
;
553 CheckArgument(!range
.isFunctionLike(), range
,
554 "cannot create higher-order function types");
555 sorts
.push_back(range
);
556 return mkTypeNode(kind::CONSTRUCTOR_TYPE
, sorts
);
559 }/* CVC4 namespace */