/*****************************************************************************/ /*! * \file context.cpp * * Author: Clark Barrett * * Created: Fri Jan 17 14:30:37 2003 * *
* * License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include "context.h" using namespace CVC3; using namespace std; vector ContextMemoryManager::s_freePages; /////////////////////////////////////////////////////////////////////////////// // Scope methods // /////////////////////////////////////////////////////////////////////////////// void Scope::finalize(void) { ContextObjChain* obj = d_restoreChain; while (obj != NULL) { ContextObjChain* tmp = obj->d_restoreChainNext; // When called from ~ContextManager(), the master objects may // still point to this scope. Disconnect them here. if (obj->d_master != NULL) { if (obj->d_master->d_scope == this) obj->d_master->d_scope = NULL; if (obj->d_master->d_restore == obj) obj->d_master->d_restore = NULL; } obj = tmp; } } void Scope::check(void) { IF_DEBUG( ContextObjChain* obj = d_restoreChain; if (debugger.trace("memory") && obj != NULL) { ostream& os = debugger.getOS(); int n(0); ContextObjChain* tmp = obj; while(tmp != NULL) { tmp = tmp->d_restoreChainNext; n++; } os << "*** Warning: ~Scope(): found "<< n << " leaked objects " << "in scope " << d_level << ":" << endl; if (debugger.flag("memory leaks")) { tmp = obj; while(tmp != NULL) { os << tmp->name() << "\n"; tmp = tmp->d_restoreChainNext; } } os << flush; } ) } /////////////////////////////////////////////////////////////////////////////// // ContextObjChain methods // /////////////////////////////////////////////////////////////////////////////// ContextObjChain* ContextObjChain::restore(void) { // Assign 'next' pointer only when the master object is restored, // since this may change our next pointer (master may have other // context objects removed). DebugAssert(d_master != NULL, "How did this happen"); // if (d_master == NULL) return d_restoreChainNext; ContextObjChain* next; DebugAssert(d_data != NULL, "Shouldn't happen"); // if (d_data == NULL) { // d_master->setNull(); // d_master->d_scope = d_master->d_scope->prevScope(); // DebugAssert(d_restore==NULL,"Expected NULL"); // next = d_restoreChainNext; // d_master->d_scope->addToChain(this); // } // else { d_master->restoreData(d_data); d_master->d_scope = d_data->d_scope; d_master->d_restore = d_restore; next = d_restoreChainNext; if (d_data != NULL) delete d_data; DebugAssert(d_master->d_restore != this, "points to self"); // } return next; } #ifdef DEBUG std::string ContextObjChain::name() const { DebugAssert(d_master != NULL, "NULL master"); return d_master->name(); } #endif /////////////////////////////////////////////////////////////////////////////// // ContextObj methods // /////////////////////////////////////////////////////////////////////////////// void ContextObj::update(int scope) { Scope* tmpScope = d_scope; DebugAssert(scope < 0 || d_scope->level() <= scope, "ContextObj::update(scope="+int2string(scope) +"): scope < d_scope->level() = " +int2string(d_scope->level())); d_scope = d_scope->topScope(); if (scope >= 0) { // Fetch the specified scope for(int i=level(); i>scope; --i) { d_scope = d_scope->prevScope(); DebugAssert(d_scope != NULL, "ContextObj::update[" +name()+"]: d_scope == NULL"); } } ContextObj* data = makeCopy(getCMM()); data->d_scope = tmpScope; // The destructor of the copy should not destroy our older copies data->d_restore=NULL; IF_DEBUG(data->setName(name()+" [copy]")); d_restore = new(getCMM()) ContextObjChain(data, this, d_restore); d_scope->addToChain(d_restore); } ContextObj::~ContextObj() { // Delete our restore copies IF_DEBUG(FatalAssert(d_active, "~ContextObj["+name()+"]")); IF_DEBUG(d_active=false); for(ContextObjChain* obj = d_restore; obj != NULL; ) { ContextObjChain* tmp = obj->d_restore; // Remove the object from the restore chain if(obj->d_restoreChainNext != NULL) obj->d_restoreChainNext->d_restoreChainPrev = obj->d_restoreChainPrev; *(obj->d_restoreChainPrev) = obj->d_restoreChainNext; // if (obj->d_data != NULL) delete obj->d_data; obj->d_master = NULL; if (tmp == NULL) { delete obj; free(obj); break; } obj = tmp; } // TRACE("context verbose", "~ContextObj()[", this, "] }"); } /////////////////////////////////////////////////////////////////////////////// // Context methods // /////////////////////////////////////////////////////////////////////////////// Context::Context(ContextManager* cm, const string& name, int id) : d_cm(cm), d_name(name), d_id(id) { ContextMemoryManager* cmm = new ContextMemoryManager(); d_topScope = new(cmm) Scope(this, cmm); d_bottomScope = d_topScope; TRACE("context", "*** [context] Creating new context: name = " + name + "id = ", id, ""); } // Don't pop, just delete everything. At this point, most of the // system is already destroyed, popping may be dangerous. Context::~Context() { // popto(0); Scope* top = d_topScope; while(top != NULL) { top = d_topScope->prevScope(); d_topScope->finalize(); delete d_topScope->getCMM(); d_topScope = top; } while (!d_cmmStack.empty()) { delete d_cmmStack.back(); d_cmmStack.pop_back(); } ContextMemoryManager::garbageCollect(); // Erase ourselves from the notify objects, so they don't call us for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i!=iend; ++i) { (*i)->d_context = NULL; } } void Context::push() { IF_DEBUG( string indentStr(level(), ' '); TRACE("pushpop", indentStr, "Push", " {"); ) ContextMemoryManager* cmm; if (!d_cmmStack.empty()) { cmm = d_cmmStack.back(); d_cmmStack.pop_back(); } else { cmm = new ContextMemoryManager(); } cmm->push(); d_topScope = new(cmm) Scope(this, cmm, d_topScope); // TRACE("context", "*** [context] Pushing scope to level ", level(), " {"); IF_DEBUG(DebugCounter maxLevel(debugger.counter("max scope level"))); IF_DEBUG(if(maxLevelprevScope() != NULL, "Illegal to pop last scope off of stack."); // Notify before popping the scope for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i != iend; ++i) (*i)->notifyPre(); // Pop the scope d_topScope = top->prevScope(); top->restore(); IF_DEBUG(top->check()); ContextMemoryManager* cmm = top->getCMM(); cmm->pop(); d_cmmStack.push_back(cmm); // Notify after the pop is done for(vector::iterator i=d_notifyObjList.begin(), iend=d_notifyObjList.end(); i != iend; ++i) (*i)->notify(); // TRACE("context", "*** [context] Popped scope to level ", level(), "}"); IF_DEBUG( string indentStr(level(), ' '); TRACE("pushpop", indentStr, "}", " Pop"); ) } void Context::popto(int toLevel) { while (toLevel < topScope()->level()) pop(); } void Context::deleteNotifyObj(ContextNotifyObj* obj) { size_t i(0), iend(d_notifyObjList.size()); for(; igetCMM()->getMemory(); cout << "Scope " << scope->level() << ": " << mem << endl; memory += mem; scope = scope->prevScope(); } mem = 0; for (unsigned long i = 0; i < d_cmmStack.size(); ++i) { mem += d_cmmStack[i]->getMemory(); } cout << "Stack: " << mem << endl; return memory + mem; } /////////////////////////////////////////////////////////////////////////////// // ContextManager methods // /////////////////////////////////////////////////////////////////////////////// ContextManager::ContextManager() { d_curContext = createContext("default"); } ContextManager::~ContextManager() { while (d_contexts.size()) { delete d_contexts.back(); d_contexts.pop_back(); } } Context* ContextManager::createContext(const string& name) { d_contexts.push_back(new Context(this, name, d_contexts.size())); return d_contexts.back(); } Context* ContextManager::switchContext(Context* context) { FatalAssert(false, "Multiple contexts not yet implemented"); Context* old = d_curContext; DebugAssert(context && context == d_contexts[context->id()], "Unknown context"); d_curContext = context; // TODO: Fix up all Context Objects return old; } unsigned long ContextManager::getMemory() { return d_curContext->getMemory(); }