Index: include/Ice/GC.h =================================================================== RCS file: /home/cvsroot/ice/include/Ice/GC.h,v retrieving revision 1.1 diff -c -r1.1 GC.h *** include/Ice/GC.h 4 Jul 2005 01:48:56 -0000 1.1 --- include/Ice/GC.h 9 Jan 2006 01:38:47 -0000 *************** *** 13,19 **** #include #include #include ! #include #include namespace IceInternal --- 13,19 ---- #include #include #include ! #include #include namespace IceInternal Index: include/Ice/GCShared.h =================================================================== RCS file: /home/cvsroot/ice/include/Ice/GCShared.h,v retrieving revision 1.1 diff -c -r1.1 GCShared.h *** include/Ice/GCShared.h 4 Jul 2005 01:48:56 -0000 1.1 --- include/Ice/GCShared.h 9 Jan 2006 01:38:48 -0000 *************** *** 40,48 **** --- 40,54 ---- virtual void __incRef(); // First derived class with class data members overrides this. virtual void __decRef(); // Ditto. + virtual void __addObject(GCObjectMultiSet&) {} // Ditto. + virtual bool __usesClasses() { return false; } // Ditto. + virtual int __getRef() const; virtual void __setNoDelete(bool); + virtual void __gcReachable(GCObjectMultiSet&) const = 0; + virtual void __gcClear() = 0; + int __getRefUnsafe() const { return _ref; *************** *** 53,65 **** --_ref; } - virtual void __gcReachable(GCObjectMultiSet&) const = 0; - virtual void __gcClear() = 0; - protected: - static void __addObject(GCObjectMultiSet&, GCShared*); - int _ref; bool _noDelete; --- 59,66 ---- Index: src/Ice/GC.cpp =================================================================== RCS file: /home/cvsroot/ice/src/Ice/GC.cpp,v retrieving revision 1.1 diff -r1.1 GC.cpp 38c38 < using namespace std; --- > using namespace std; 163,177c163,164 < // < // gcObjects contains the set of class instances that have at least one member of class type, < // that is, gcObjects contains all those instances that can point at other instances. < // Call this the the candiate set. < // Build a multiset of instances that are immediately (not recursively) reachable from instances < // in the candidate set. This adds leaf nodes (class instances that are pointed at, but cannot < // point at anything themselves) to the multiset. < // < GCObjectMultiSet reachable; < { < for(GCObjectSet::const_iterator i = gcObjects.begin(); i != gcObjects.end(); ++i) < { < (*i)->__gcReachable(reachable); < } < } --- > typedef map CountMap; > CountMap counts; 179,183d165 < // < // Create a map of reference counts. < // < typedef map ObjectCounts; < ObjectCounts counts; 185,186c167,176 < ObjectCounts::iterator pos; < for(GCObjectMultiSet::const_iterator i = reachable.begin(); i != reachable.end(); ++i) --- > // > // gcObjects contains the set of class instances that have at least one member of class type, > // that is, gcObjects contains all those instances that can point at other instances. > // > // Create a map that, for each object in gcObjects, contains an pair. > // In addition, for each object in gcObjects, add the objects that are immediately (not > // recursively) reachable from that object to a multiset. (We use a multiset because a > // single object can be pointed at several times, either by itself or by other objects.) > // > GCObjectMultiSet reachable; 188,194c178 < pos = counts.find(*i); < < // < // If this instance is not in the counts set yet, insert it with its reference count - 1; < // otherwise, decrement its reference count. < // < if(pos == counts.end()) --- > for(GCObjectSet::const_iterator i = gcObjects.begin(); i != gcObjects.end(); ++i) 196c180,181 < counts.insert(pos, ObjectCounts::value_type(*i, (*i)->__getRefUnsafe() - 1)); --- > counts.insert(CountMap::value_type(*i, (*i)->__getRefUnsafe())); > (*i)->__gcReachable(reachable); 198c183,191 < else --- > } > > // > // Decrement the reference count in the counts map once once for each entry in the multiset. > // This drops the reference count of each map entry once for each time the corrsponding object > // is pointed at. > // > { > for(GCObjectMultiSet::const_iterator i = reachable.begin(); i != reachable.end(); ++i) 199a193,194 > CountMap::iterator pos = counts.find(*i); > assert(pos != counts.end()); 205,209d199 < // < // Any instances with a ref count > 0 are referenced from outside the set of class instances (and therefore < // reachable from the program, for example, via Ptr variable on the stack). Remove these instances < // (and all instances reachable from them) from the overall set of objects. < // 210a201,206 > // > // Any instances with a ref count > 0 are referenced from outside the objects in gcObjects (and > // are therefore reachable from the program, for example, via Ptr variable on the stack). The set > // of live objects therefore are all the objects with a reference count > 0, as well as all > // objects that are (recursively) reachable from these objects. > // 212d207 < for(ObjectCounts::const_iterator i = counts.begin(); i != counts.end(); ++i) 214c209 < if(i->second > 0) --- > for(CountMap::const_iterator i = counts.begin(); i != counts.end(); ++i) 216c211,214 < recursivelyReachable(i->first, liveObjects); --- > if(i->second > 0) > { > recursivelyReachable(i->first, liveObjects); > } 220c218,220 < for(GCObjectSet::const_iterator j = liveObjects.begin(); j != liveObjects.end(); ++j) --- > // > // Remove all live objects from the map. > // 222c222,229 < counts.erase(*j); --- > for(GCObjectSet::const_iterator i = liveObjects.begin(); i != liveObjects.end(); ++i) > { > #ifndef NDEBUG > bool erased = > #endif > counts.erase(*i); > assert(erased); > } 227c234 < // What is left in the counts set can be garbage collected. --- > // What is left in the counts map can be garbage collected. 230c237 < ObjectCounts::const_iterator i; --- > CountMap::const_iterator i; 233c240,248 < i->first->__gcClear(); // Decrement ref count of objects pointed at by this object. --- > // > // For classes with members that point at potentially-cyclic instances, __gcClear() > // decrements the reference count of those instances and clears the > // corrsponding Ptr members. > // For classes that cannot be part of a cycle (because they do not contain class members) > // and are therefore true leaves, __gcClear() assigns 0 to the corresponding class member, > // which either decrements the ref count or, if it reaches zero, deletes the instance as usual. > // > i->first->__gcClear(); Index: src/Ice/GCShared.cpp =================================================================== RCS file: /home/cvsroot/ice/src/Ice/GCShared.cpp,v retrieving revision 1.1 diff -c -r1.1 GCShared.cpp *** src/Ice/GCShared.cpp 4 Jul 2005 01:48:11 -0000 1.1 --- src/Ice/GCShared.cpp 9 Jan 2006 01:38:50 -0000 *************** *** 73,86 **** _noDelete = b; gcRecMutex._m->unlock(); } - - void - IceInternal::GCShared::__addObject(GCObjectMultiSet& c, GCShared* p) - { - gcRecMutex._m->lock(); - if(p) - { - c.insert(p); - } - gcRecMutex._m->unlock(); - } --- 73,75 ---- Index: src/slice2cpp/Gen.cpp =================================================================== RCS file: /home/cvsroot/ice/src/slice2cpp/Gen.cpp,v retrieving revision 1.271 diff -c -r1.271 Gen.cpp *** src/slice2cpp/Gen.cpp 14 Nov 2005 02:15:44 -0000 1.271 --- src/slice2cpp/Gen.cpp 9 Jan 2006 01:38:52 -0000 *************** *** 3161,3170 **** // // A class can potentially be part of a cycle if it (recursively) contains class ! // members. If so, we override __incRef() and __decRef() and, hence, consider instances ! // of the class as candidates for collection by the garbage collector. ! // We override __incRef() and __decRef() only once, in the basemost potentially cyclic class ! // in an inheritance hierarchy. // bool hasBaseClass = !bases.empty() && !bases.front()->isInterface(); bool canBeCyclic = p->canBeCyclic(); --- 3161,3170 ---- // // A class can potentially be part of a cycle if it (recursively) contains class ! // members. If so, we override __incRef(), __decRef(), and __addObject() and, hence, consider ! // instances of the class as candidates for collection by the garbage collector. ! // We override __incRef(), __decRef(), and __addObject() only once, in the basemost potentially ! // cyclic class in an inheritance hierarchy. // bool hasBaseClass = !bases.empty() && !bases.front()->isInterface(); bool canBeCyclic = p->canBeCyclic(); *************** *** 3227,3232 **** --- 3227,3246 ---- C << nl << "delete this;"; C << eb; C << eb; + + H << nl << "virtual void __addObject(::IceInternal::GCObjectMultiSet&);"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__addObject(::IceInternal::GCObjectMultiSet& _c)"; + C << sb; + C << nl << "_c.insert(this);"; + C << eb; + + H << nl << "virtual bool __usesClasses();"; + + C << sp << nl << "bool" << nl << scoped.substr(2) << "::__usesClasses()"; + C << sb; + C << nl << "return true;"; + C << eb; } // *************** *** 3282,3288 **** if((BuiltinPtr::dynamicCast(p) && BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(p)) { ! C << nl << "__addObject(_c, " << prefix << name << ".get());"; } else if(StructPtr s = StructPtr::dynamicCast(p)) { --- 3296,3305 ---- if((BuiltinPtr::dynamicCast(p) && BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(p)) { ! C << nl << "if(" << prefix << name << ')'; ! C << sb; ! C << nl << prefix << name << "->__addObject(_c);"; ! C << eb; } else if(StructPtr s = StructPtr::dynamicCast(p)) { *************** *** 3333,3341 **** --- 3350,3365 ---- { C << nl << "if(" << prefix << name << ")"; C << sb; + C << nl << "if(" << prefix << name << "->__usesClasses())"; + C << sb; C << nl << prefix << name << "->__decRefUnsafe();"; C << nl << prefix << name << ".__clearHandleUnsafe();"; C << eb; + C << nl << "else"; + C << sb; + C << nl << prefix << name << " = 0;"; + C << eb; + C << eb; } else if(StructPtr s = StructPtr::dynamicCast(p)) { Index: test/Ice/gc/Client.cpp =================================================================== RCS file: /home/cvsroot/ice/test/Ice/gc/Client.cpp,v retrieving revision 1.15 diff -r1.15 Client.cpp 530a531,555 > NNPtr nn = new NN; > nn->l = new NL; > test(getNum() == 2); > Ice::collectGarbage(); > test(getNum() == 2); > } > Ice::collectGarbage(); > test(getNum() == 0); > > { > NLPtr p; > { > NNPtr nn = new NN; > p = new NL; > nn->l = p; > test(getNum() == 2); > Ice::collectGarbage(); > test(getNum() == 2); > } > Ice::collectGarbage(); > test(getNum() == 1); > } > test(getNum() == 0); > > { 566a592,602 > { > NNPtr nn1 = new NN; > nn1->n = new NN; > test(getNum() == 2); > Ice::collectGarbage(); > test(getNum() == 2); > } > test(getNum() == 0); > Ice::collectGarbage(); > test(getNum() == 0); >