Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
23 kB · 809 lines
C++
at develop
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/* * Main authors: * Guido Tack <guido.tack@monash.edu> */
/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <minizinc/ast.hh>#include <minizinc/config.hh>#include <minizinc/gc.hh>#include <minizinc/hash.hh>#include <minizinc/model.hh>#include <minizinc/support/dtrace.h>#include <minizinc/timer.hh>
#include <cstring>#include <vector>
//#define MINIZINC_GC_STATS
#if defined(MINIZINC_GC_STATS)#include <map>#endif
namespace MiniZinc {
GC*& GC::gc(void) {#if defined(HAS_DECLSPEC_THREAD) __declspec(thread) static GC* gc = NULL;#elif defined(HAS_ATTR_THREAD) static __thread GC* gc = NULL;#else#error Need thread-local storage#endif return gc;}
bool GC::locked(void) { assert(gc()); return gc()->_lock_count > 0;}
GCLock::GCLock(void) { GC::lock(); }GCLock::~GCLock(void) { GC::unlock(); }
class FreeListNode : public ASTNode {public: FreeListNode* next; size_t size; FreeListNode(size_t s, FreeListNode* n) : ASTNode(ASTNode::NID_FL), next(n), size(s) { _gc_mark = 1; } FreeListNode(size_t s) : ASTNode(ASTNode::NID_FL), next(NULL), size(s) {}};
class HeapPage {public: HeapPage* next; size_t size; size_t used; char data[1]; HeapPage(HeapPage* n, size_t s) : next(n), size(s), used(0) {}};
/// Memory managed by the garbage collectorclass GC::Heap { friend class GC;#if defined(MINIZINC_GC_STATS) static const char* _nodeid[Item::II_END + 1]; struct GCStat { int first; int second; int keepalive; int inmodel; size_t total; GCStat(void) : first(0), second(0), keepalive(0), inmodel(0), total(0) {} }; std::map<int, GCStat> gc_stats;#endifprotected: static const size_t _min_gc_threshold;
HeapPage* _page; Model* _rootset; KeepAlive* _roots; WeakRef* _weakRefs; ASTNodeWeakMap* _nodeWeakMaps; static const int _max_fl = 5; FreeListNode* _fl[_max_fl + 1]; static const size_t _fl_size[_max_fl + 1]; int _fl_slot(size_t _size) { size_t size = _size; assert(size <= _fl_size[_max_fl]); assert(size >= _fl_size[0]); size -= sizeof(Item); assert(size % sizeof(void*) == 0); size /= sizeof(void*); assert(size >= 1); int slot = static_cast<int>(size) - 1; return slot; }
/// Total amount of memory allocated size_t _alloced_mem; /// Total amount of memory currently free size_t _free_mem; /// Memory threshold for next garbage collection size_t _gc_threshold; /// High water mark of all allocated memory size_t _max_alloced_mem;
/// A trail item struct TItem { Expression** l; Expression* v; bool mark; TItem(Expression** l0, Expression* v0) : l(l0), v(v0), mark(false) {} }; /// Trail std::vector<TItem> trail;
Heap(void) : _page(NULL), _rootset(NULL), _roots(NULL), _weakRefs(NULL), _nodeWeakMaps(NULL), _alloced_mem(0), _free_mem(0), _gc_threshold(_min_gc_threshold), _max_alloced_mem(0) { for (int i = _max_fl + 1; i--;) _fl[i] = NULL; }
/// Default size of pages to allocate static const size_t pageSize = 1 << 20;
HeapPage* allocPage(size_t s, bool exact = false) { if (!exact) s = std::max(s, pageSize); HeapPage* newPage = static_cast<HeapPage*>(::malloc(sizeof(HeapPage) + s - 1)); if (newPage == NULL) { throw InternalError("out of memory"); }#ifndef NDEBUG memset(newPage, 255, sizeof(HeapPage) + s - 1);#endif _alloced_mem += s; _max_alloced_mem = std::max(_max_alloced_mem, _alloced_mem); _free_mem += s; if (exact && _page) { new (newPage) HeapPage(_page->next, s); _page->next = newPage; } else { if (_page) { size_t ns = _page->size - _page->used; assert(ns <= _fl_size[_max_fl]); if (ns >= _fl_size[0]) { // Remainder of page can be added to free lists FreeListNode* fln = reinterpret_cast<FreeListNode*>(_page->data + _page->used); _page->used += ns; new (fln) FreeListNode(ns, _fl[_fl_slot(ns)]); _fl[_fl_slot(ns)] = fln; } else { // Waste a little memory (less than smallest free list slot) _free_mem -= ns; assert(_alloced_mem >= _free_mem); } } new (newPage) HeapPage(_page, s); _page = newPage; } return newPage; }
void* alloc(size_t size, bool exact = false) { assert(size <= 80 || exact); /// Align to word boundary size += ((8 - (size & 7)) & 7); HeapPage* p = _page; if (exact || _page == NULL || _page->used + size >= _page->size) p = allocPage(size, exact); char* ret = p->data + p->used; p->used += size; _free_mem -= size; if (p->size - p->used < _fl_size[0]) { _free_mem -= (p->size - p->used); _alloced_mem -= (p->size - p->used); p->size = p->used; } assert(_alloced_mem >= _free_mem); return ret; }
/// Allocate one object of type T (no initialisation) template <typename T> T* alloc(void) { return static_cast<T*>(alloc(sizeof(T))); }
/// Allocate \a n objects of type T (no initialisation) template <typename T> T* alloc(int n) { return static_cast<T*>(alloc(n * sizeof(T))); }
void* fl(size_t size) { int slot = _fl_slot(size); assert(slot <= _max_fl); if (_fl[slot]) { FreeListNode* p = _fl[slot]; _fl[slot] = p->next; _free_mem -= size; return p; } return alloc(size); }
void trigger(void) { DTRACE0(GC_START);#ifdef MINIZINC_GC_STATS std::cerr << "GC\n\talloced " << (_alloced_mem / 1024) << "\n\tfree " << (_free_mem / 1024) << "\n\tdiff " << ((_alloced_mem - _free_mem) / 1024) << "\n\tthreshold " << (_gc_threshold / 1024) << "\n";#endif size_t old_free = _free_mem; mark(); sweep(); // GC strategy: // increase threshold if either // a) we haven't been able to put much on the free list (comapred to before GC), or // b) the free list memory (after GC) is less than 50% of the allocated memory // otherwise (i.e., we have been able to increase the free list, and it is now more // than 50% of overall allocated memory), keep threshold at allocated memory if ((old_free != 0 && static_cast<double>(old_free) / static_cast<double>(_free_mem) > 0.9) || static_cast<double>(_free_mem) / _alloced_mem < 0.5) { _gc_threshold = std::max(_min_gc_threshold, static_cast<size_t>(_alloced_mem * 1.5)); } else { _gc_threshold = std::max(_min_gc_threshold, _alloced_mem); }#ifdef MINIZINC_GC_STATS std::cerr << "done\n\talloced " << (_alloced_mem / 1024) << "\n\tfree " << (_free_mem / 1024) << "\n\tdiff " << ((_alloced_mem - _free_mem) / 1024) << "\n\tthreshold " << (_gc_threshold / 1024) << "\n";#endif DTRACE0(GC_END); } void rungc(void) { if (_alloced_mem > _gc_threshold) { trigger(); } } void mark(void); void sweep(void);
static size_t nodesize(ASTNode* n) { static const size_t _nodesize[Item::II_END + 1] = { 0, // NID_FL 0, // NID_CHUNK 0, // NID_VEC sizeof(IntLit), // E_INTLIT sizeof(FloatLit), // E_FLOATLIT sizeof(SetLit), // E_SETLIT sizeof(BoolLit), // E_BOOLLIT sizeof(StringLit), // E_STRINGLIT sizeof(Id), // E_ID sizeof(AnonVar), // E_ANON sizeof(ArrayLit), // E_ARRAYLIT sizeof(ArrayAccess), // E_ARRAYACCESS sizeof(Comprehension), // E_COMP sizeof(ITE), // E_ITE sizeof(BinOp), // E_BINOP sizeof(UnOp), // E_UNOP sizeof(Call), // E_CALL sizeof(VarDecl), // E_VARDECL sizeof(Let), // E_LET sizeof(TypeInst), // E_TI sizeof(TIId), // E_TIID sizeof(IncludeI), // II_INC sizeof(VarDeclI), // II_VD sizeof(AssignI), // II_ASN sizeof(ConstraintI), // II_CON sizeof(SolveI), // II_SOL sizeof(OutputI), // II_OUT sizeof(FunctionI) // II_FUN }; size_t ns; switch (n->_id) { case ASTNode::NID_FL: ns = static_cast<FreeListNode*>(n)->size; break; case ASTNode::NID_CHUNK: ns = static_cast<ASTChunk*>(n)->memsize(); break; case ASTNode::NID_VEC: ns = static_cast<ASTVec*>(n)->memsize(); break; default: assert(n->_id <= Item::II_END); ns = _nodesize[n->_id]; break; } ns += ((8 - (ns & 7)) & 7); return ns; }};
const size_t GC::Heap::_min_gc_threshold = 10ll * 1024ll;
#ifdef MINIZINC_GC_STATSconst char* GC::Heap::_nodeid[] = { "FreeList ", // NID_FL "Chunk ", // NID_CHUNK "Vec ", // NID_VEC "IntLit ", // E_INTLIT "FloatLit ", // E_FLOATLIT "SetLit ", // E_SETLIT "BoolLit ", // E_BOOLLIT "StringLit ", // E_STRINGLIT "Id ", // E_ID "AnonVar ", // E_ANON "ArrayLit ", // E_ARRAYLIT "ArrayAccess ", // E_ARRAYACCESS "Comprehension ", // E_COMP "ITE ", // E_ITE "BinOp ", // E_BINOP "UnOp ", // E_UNOP "Call ", // E_CALL "VarDecl ", // E_VARDECL "Let ", // E_LET "TypeInst ", // E_TI "TIId ", // E_TIID "IncludeI ", // II_INC "VarDeclI ", // II_VD "AssignI ", // II_ASN "ConstraintI ", // II_CON "SolveI ", // II_SOL "OutputI ", // II_OUT "FunctionI " // II_FUN};#endif
void GC::setTimeout(unsigned long long int t) { if (gc() == NULL) { gc() = new GC(); } gc()->_timeout = t; gc()->_timeout_timer.reset();}
void GC::lock(void) { if (gc() == NULL) { gc() = new GC(); } // If a timeout has been specified, first check counter // before checking timer (counter is much cheaper, introduces // less overhead) if (gc()->_timeout > 0 && gc()->_timeout_counter++ > 500) { gc()->_timeout_counter = 0; if (gc()->_timeout_timer.ms() > gc()->_timeout) { gc()->_timeout = 0; gc()->_timeout_counter = 0; throw Timeout(); } } if (gc()->_lock_count == 0) { gc()->_heap->rungc(); } gc()->_lock_count++;}void GC::unlock(void) { assert(locked()); gc()->_lock_count--;}
void GC::trigger(void) { if (!locked()) gc()->_heap->trigger();}
const size_t GC::Heap::pageSize;
const size_t GC::Heap::_fl_size[GC::Heap::_max_fl + 1] = { sizeof(Item) + 1 * sizeof(void*), sizeof(Item) + 2 * sizeof(void*), sizeof(Item) + 3 * sizeof(void*), sizeof(Item) + 4 * sizeof(void*), sizeof(Item) + 5 * sizeof(void*), sizeof(Item) + 6 * sizeof(void*),};
GC::GC(void) : _heap(new Heap()), _lock_count(0), _timeout(0), _timeout_counter(0) {}
void GC::add(Model* m) { GC* gc = GC::gc(); if (gc->_heap->_rootset) { m->_roots_next = gc->_heap->_rootset; m->_roots_prev = m->_roots_next->_roots_prev; m->_roots_prev->_roots_next = m; m->_roots_next->_roots_prev = m; } else { gc->_heap->_rootset = m->_roots_next = m->_roots_prev = m; }}
void GC::remove(Model* m) { GC* gc = GC::gc(); if (m->_roots_next == m) { gc->_heap->_rootset = NULL; } else { m->_roots_next->_roots_prev = m->_roots_prev; m->_roots_prev->_roots_next = m->_roots_next; if (m == gc->_heap->_rootset) gc->_heap->_rootset = m->_roots_prev; }}
void* GC::alloc(size_t size) { assert(locked()); void* ret; if (size < _heap->_fl_size[0] || size > _heap->_fl_size[_heap->_max_fl]) { ret = _heap->alloc(size, true); } else { ret = _heap->fl(size); } new (ret) FreeListNode(size); return ret;}
void GC::Heap::mark(void) {#if defined(MINIZINC_GC_STATS) std::cerr << "================= mark =================: "; gc_stats.clear();#endif
for (KeepAlive* e = _roots; e != NULL; e = e->next()) { if ((*e)() && (*e)()->_gc_mark == 0) { Expression::mark((*e)());#if defined(MINIZINC_GC_STATS) gc_stats[(*e)()->_id].keepalive++;#endif } }#if defined(MINIZINC_GC_STATS) std::cerr << "+";#endif
Model* m = _rootset; if (m == NULL) return; do { m->_filepath.mark(); m->_filename.mark(); for (unsigned int j = 0; j < m->_items.size(); j++) { Item* i = m->_items[j]; if (i->_gc_mark == 0) { i->_gc_mark = 1; i->loc().mark(); switch (i->iid()) { case Item::II_INC: i->cast<IncludeI>()->f().mark(); break; case Item::II_VD: Expression::mark(i->cast<VarDeclI>()->e());#if defined(MINIZINC_GC_STATS) gc_stats[i->cast<VarDeclI>()->e()->Expression::eid()].inmodel++;#endif break; case Item::II_ASN: i->cast<AssignI>()->id().mark(); Expression::mark(i->cast<AssignI>()->e()); Expression::mark(i->cast<AssignI>()->decl()); break; case Item::II_CON: Expression::mark(i->cast<ConstraintI>()->e());#if defined(MINIZINC_GC_STATS) gc_stats[i->cast<ConstraintI>()->e()->Expression::eid()].inmodel++;#endif break; case Item::II_SOL: { SolveI* si = i->cast<SolveI>(); for (ExpressionSetIter it = si->ann().begin(); it != si->ann().end(); ++it) { Expression::mark(*it); } } Expression::mark(i->cast<SolveI>()->e()); break; case Item::II_OUT: Expression::mark(i->cast<OutputI>()->e()); break; case Item::II_FUN: { FunctionI* fi = i->cast<FunctionI>(); fi->id().mark(); Expression::mark(fi->ti()); for (ExpressionSetIter it = fi->ann().begin(); it != fi->ann().end(); ++it) { Expression::mark(*it); } Expression::mark(fi->e()); fi->params().mark(); for (unsigned int k = 0; k < fi->params().size(); k++) { Expression::mark(fi->params()[k]); } } break; } } } m = m->_roots_next; } while (m != _rootset);
for (unsigned int i = static_cast<unsigned int>(trail.size()); i--;) { Expression::mark(trail[i].v); }
bool fixPrev = false; WeakRef* prevWr = NULL; for (WeakRef* wr = _weakRefs; wr != NULL; wr = wr->next()) { if (fixPrev) { fixPrev = false; removeWeakRef(prevWr); prevWr->_n = NULL; prevWr->_p = NULL; } if ((*wr)() && (*wr)()->_gc_mark == 0) { wr->_e = NULL; wr->_valid = false; fixPrev = true; prevWr = wr; } } if (fixPrev) { removeWeakRef(prevWr); prevWr->_n = NULL; prevWr->_p = NULL; }
for (ASTNodeWeakMap* wr = _nodeWeakMaps; wr != NULL; wr = wr->next()) { std::vector<ASTNode*> toRemove; for (auto n : wr->_m) { if (n.first->_gc_mark == 0 || n.second->_gc_mark == 0) toRemove.push_back(n.first); } for (auto n : toRemove) { wr->_m.erase(n); } }
#if defined(MINIZINC_GC_STATS) std::cerr << "+"; std::cerr << "\n";#endif}
void GC::Heap::sweep(void) {#if defined(MINIZINC_GC_STATS) std::cerr << "=============== GC sweep =============\n";#endif HeapPage* p = _page; HeapPage* prev = NULL; while (p) { size_t off = 0; bool wholepage = true; struct NodeInfo { ASTNode* n; size_t ns; NodeInfo(ASTNode* n0, size_t ns0) : n(n0), ns(ns0) {} }; std::vector<NodeInfo> freeNodes; freeNodes.reserve(100); while (off < p->used) { ASTNode* n = reinterpret_cast<ASTNode*>(p->data + off); size_t ns = nodesize(n); assert(ns != 0);#if defined(MINIZINC_GC_STATS) GCStat& stats = gc_stats[n->_id]; stats.first++; stats.total += ns;#endif if (n->_gc_mark == 0) { switch (n->_id) { case Item::II_FUN: static_cast<FunctionI*>(n)->ann().~Annotation(); break; case Item::II_SOL: static_cast<SolveI*>(n)->ann().~Annotation(); break; case Expression::E_VARDECL: // Reset WeakRef inside VarDecl static_cast<VarDecl*>(n)->flat(NULL); // fall through default: if (n->_id >= ASTNode::NID_END + 1 && n->_id <= Expression::EID_END) { static_cast<Expression*>(n)->ann().~Annotation(); } } if (ns >= _fl_size[0] && ns <= _fl_size[_max_fl]) { freeNodes.push_back(NodeInfo(n, ns)); } else { assert(off == 0); assert(p->used == p->size); } } else {#if defined(MINIZINC_GC_STATS) stats.second++;#endif wholepage = false; if (n->_id != ASTNode::NID_FL) n->_gc_mark = 0; } off += ns; } if (wholepage) {#ifndef NDEBUG memset(p->data, 42, p->size);#endif if (prev) { prev->next = p->next; } else { assert(p == _page); _page = p->next; } HeapPage* pf = p; p = p->next; _alloced_mem -= pf->size; if (pf->size - pf->used >= _fl_size[0]) _free_mem -= (pf->size - pf->used); assert(_alloced_mem >= _free_mem); ::free(pf); } else { for (auto ni : freeNodes) { FreeListNode* fln = static_cast<FreeListNode*>(ni.n); new (fln) FreeListNode(ni.ns, _fl[_fl_slot(ni.ns)]); _fl[_fl_slot(ni.ns)] = fln; _free_mem += ni.ns;#if defined(MINIZINC_GC_STATS) gc_stats[fln->_id].second++;#endif } assert(_alloced_mem >= _free_mem); prev = p; p = p->next; } }#if defined(MINIZINC_GC_STATS) for (auto stat : gc_stats) { std::cerr << _nodeid[stat.first] << ":\t" << stat.second.first << " / " << stat.second.second << " / " << stat.second.keepalive << " / " << stat.second.inmodel << " / "; if (stat.second.total > 1024) { if (stat.second.total > 1024 * 1024) { std::cerr << (stat.second.total / 1024 / 1024) << "M"; } else { std::cerr << (stat.second.total / 1024) << "K"; } } else { std::cerr << (stat.second.total); } std::cerr << std::endl; }#endif}
ASTVec::ASTVec(size_t size) : ASTNode(NID_VEC), _size(size) {}void* ASTVec::alloc(size_t size) { size_t s = sizeof(ASTVec) + (size <= 2 ? 0 : size - 2) * sizeof(void*); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s);}
ASTChunk::ASTChunk(size_t size) : ASTNode(NID_CHUNK), _size(size) {}void* ASTChunk::alloc(size_t size) { size_t s = sizeof(ASTChunk) + (size <= 4 ? 0 : size - 4) * sizeof(char); s += ((8 - (s & 7)) & 7); return GC::gc()->alloc(s);}
void GC::mark(void) { GC* gc = GC::gc(); if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = true;}void GC::trail(Expression** l, Expression* v) { GC* gc = GC::gc(); gc->_heap->trail.push_back(GC::Heap::TItem(l, v));}void GC::untrail(void) { GC* gc = GC::gc(); while (!gc->_heap->trail.empty() && !gc->_heap->trail.back().mark) { *gc->_heap->trail.back().l = gc->_heap->trail.back().v; gc->_heap->trail.pop_back(); } if (!gc->_heap->trail.empty()) gc->_heap->trail.back().mark = false;}size_t GC::maxMem(void) { GC* gc = GC::gc(); return gc->_heap->_max_alloced_mem;}
void* ASTNode::operator new(size_t size) { return GC::gc()->alloc(size); }
void GC::addKeepAlive(KeepAlive* e) { assert(e->_p == NULL); assert(e->_n == NULL); e->_n = GC::gc()->_heap->_roots; if (GC::gc()->_heap->_roots) GC::gc()->_heap->_roots->_p = e; GC::gc()->_heap->_roots = e;}void GC::removeKeepAlive(KeepAlive* e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_roots == e); GC::gc()->_heap->_roots = e->_n; } if (e->_n) { e->_n->_p = e->_p; }}
KeepAlive::KeepAlive(Expression* e) : _e(e), _p(NULL), _n(NULL) { if (_e && !_e->isUnboxedVal()) GC::gc()->addKeepAlive(this);}KeepAlive::~KeepAlive(void) { if (_e && !_e->isUnboxedVal()) GC::gc()->removeKeepAlive(this);}KeepAlive::KeepAlive(const KeepAlive& e) : _e(e._e), _p(NULL), _n(NULL) { if (_e && !_e->isUnboxedVal()) GC::gc()->addKeepAlive(this);}KeepAlive& KeepAlive::operator=(const KeepAlive& e) { if (_e && !_e->isUnboxedVal()) { if (e._e == NULL || e._e->isUnboxedVal()) { GC::gc()->removeKeepAlive(this); _p = _n = NULL; } } else { if (e._e != NULL && !e._e->isUnboxedVal()) GC::gc()->addKeepAlive(this); } _e = e._e; return *this;}
void GC::addWeakRef(WeakRef* e) { assert(e->_p == NULL); assert(e->_n == NULL); e->_n = GC::gc()->_heap->_weakRefs; if (GC::gc()->_heap->_weakRefs) GC::gc()->_heap->_weakRefs->_p = e; GC::gc()->_heap->_weakRefs = e;}void GC::removeWeakRef(MiniZinc::WeakRef* e) { if (e->_p) { e->_p->_n = e->_n; } else { assert(GC::gc()->_heap->_weakRefs == e); GC::gc()->_heap->_weakRefs = e->_n; } if (e->_n) { e->_n->_p = e->_p; }}void GC::addNodeWeakMap(ASTNodeWeakMap* m) { assert(m->_p == NULL); assert(m->_n == NULL); m->_n = GC::gc()->_heap->_nodeWeakMaps; if (GC::gc()->_heap->_nodeWeakMaps) GC::gc()->_heap->_nodeWeakMaps->_p = m; GC::gc()->_heap->_nodeWeakMaps = m;}void GC::removeNodeWeakMap(ASTNodeWeakMap* m) { if (m->_p) { m->_p->_n = m->_n; } else { assert(GC::gc()->_heap->_nodeWeakMaps == m); GC::gc()->_heap->_nodeWeakMaps = m->_n; } if (m->_n) { m->_n->_p = m->_p; }}
WeakRef::WeakRef(Expression* e) : _e(e), _p(NULL), _n(NULL), _valid(true) { if (_e && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this);}WeakRef::~WeakRef(void) { if (_e && !_e->isUnboxedVal()) GC::gc()->removeWeakRef(this);}WeakRef::WeakRef(const WeakRef& e) : _e(e()), _p(NULL), _n(NULL), _valid(true) { if (_e && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this);}WeakRef& WeakRef::operator=(const WeakRef& e) { // Test if this WeakRef is currently active in the GC bool isActive = (_e && !_e->isUnboxedVal()); if (isActive) { // Yes, active WeakRef. // If after assigning WeakRef should be inactive, remove it. if (e() == NULL || e()->isUnboxedVal()) { GC::gc()->removeWeakRef(this); _n = _p = NULL; } } _e = e(); _valid = true;
// If this WeakRef was not active but now should be, add it if (!isActive && _e != NULL && !_e->isUnboxedVal()) GC::gc()->addWeakRef(this); return *this;}
ASTNodeWeakMap::ASTNodeWeakMap(void) : _p(NULL), _n(NULL) { GC::gc()->addNodeWeakMap(this); }
ASTNodeWeakMap::~ASTNodeWeakMap(void) { GC::gc()->removeNodeWeakMap(this); }
void ASTNodeWeakMap::insert(ASTNode* n0, ASTNode* n1) { _m.insert(std::make_pair(n0, n1)); }
ASTNode* ASTNodeWeakMap::find(ASTNode* n) { NodeMap::iterator it = _m.find(n); if (it == _m.end()) return NULL; return it->second;}
} // namespace MiniZinc