diff options
-rw-r--r-- | generator/cppgenerator.cpp | 2 | ||||
-rw-r--r-- | libshiboken/basewrapper.cpp | 24 | ||||
-rw-r--r-- | libshiboken/basewrapper_p.h | 4 | ||||
-rw-r--r-- | libshiboken/bindingmanager.cpp | 40 | ||||
-rw-r--r-- | libshiboken/bindingmanager.h | 4 |
5 files changed, 69 insertions, 5 deletions
diff --git a/generator/cppgenerator.cpp b/generator/cppgenerator.cpp index 7f9c865ca..cd7f14eca 100644 --- a/generator/cppgenerator.cpp +++ b/generator/cppgenerator.cpp @@ -425,7 +425,7 @@ void CppGenerator::writeDestructorNative(QTextStream &s, const AbstractMetaClass { Indentation indentation(INDENT); s << wrapperName(metaClass) << "::~" << wrapperName(metaClass) << "()" << endl << '{' << endl; - s << INDENT << "BindingManager::instance().invalidateWrapper(this);" << endl; + s << INDENT << "BindingManager::instance().destroyWrapper(this);" << endl; s << '}' << endl; } diff --git a/libshiboken/basewrapper.cpp b/libshiboken/basewrapper.cpp index 7f674c9c2..6e8848bbc 100644 --- a/libshiboken/basewrapper.cpp +++ b/libshiboken/basewrapper.cpp @@ -173,6 +173,11 @@ void removeParent(SbkBaseWrapper* child) ChildrenList& oldBrothers = pInfo->parent->parentInfo->children; oldBrothers.remove(child); pInfo->parent = 0; + + if (pInfo->hasWrapperRef) { + Py_DECREF(child); + pInfo->hasWrapperRef = false; + } Py_DECREF(child); } @@ -220,6 +225,7 @@ void setParent(PyObject* parent, PyObject* child) removeParent(child_); // Add the child to the new parent + pInfo = child_->parentInfo; if (!parentIsNull) { if (!pInfo) pInfo = child_->parentInfo = new ParentInfo; @@ -236,11 +242,22 @@ static void _destroyParentInfo(SbkBaseWrapper* obj, bool removeFromParent) ParentInfo* pInfo = obj->parentInfo; if (removeFromParent && pInfo && pInfo->parent) removeParent(obj); + ChildrenList::iterator it = pInfo->children.begin(); for (; it != pInfo->children.end(); ++it) { SbkBaseWrapper*& child = *it; - _destroyParentInfo(child, false); - Py_DECREF(child); + + // keep this, the wrapper still alive + if (!SbkBaseWrapper_containsCppWrapper(obj) && + SbkBaseWrapper_containsCppWrapper(child) && + child->parentInfo) { + child->parentInfo->parent = 0; + child->parentInfo->hasWrapperRef = true; + SbkBaseWrapper_setOwnership(child, false); + } else { + _destroyParentInfo(child, false); + Py_DECREF(child); + } } delete pInfo; obj->parentInfo = 0; @@ -248,7 +265,7 @@ static void _destroyParentInfo(SbkBaseWrapper* obj, bool removeFromParent) void destroyParentInfo(SbkBaseWrapper* obj, bool removeFromParent) { - BindingManager::instance().invalidateWrapper(obj); + BindingManager::instance().destroyWrapper(obj); _destroyParentInfo(obj, removeFromParent); } @@ -490,6 +507,7 @@ void deallocWrapper(PyObject* pyObj) if (SbkBaseWrapper_hasParentInfo(pyObj)) destroyParentInfo(sbkObj); + clearReferences(sbkObj); Py_XDECREF(sbkObj->ob_dict); diff --git a/libshiboken/basewrapper_p.h b/libshiboken/basewrapper_p.h index e1a9a0e73..1357c89a6 100644 --- a/libshiboken/basewrapper_p.h +++ b/libshiboken/basewrapper_p.h @@ -131,11 +131,13 @@ typedef std::list<SbkBaseWrapper*> ChildrenList; struct ParentInfo { /// Default ctor. - ParentInfo() : parent(0) {} + ParentInfo() : parent(0), hasWrapperRef(false) {} /// Pointer to parent object. SbkBaseWrapper* parent; /// List of object children. ChildrenList children; + /// has internal ref + bool hasWrapperRef; }; /** diff --git a/libshiboken/bindingmanager.cpp b/libshiboken/bindingmanager.cpp index 596e7ba01..47fd77d71 100644 --- a/libshiboken/bindingmanager.cpp +++ b/libshiboken/bindingmanager.cpp @@ -102,8 +102,12 @@ static void showWrapperMap(const WrapperMap& wrapperMap) struct BindingManager::BindingManagerPrivate { WrapperMap wrapperMapper; Graph classHierarchy; + bool destroying; + + BindingManagerPrivate() : destroying(false) {} void releaseWrapper(void* cptr); void assignWrapper(PyObject* wrapper, const void* cptr); + }; void BindingManager::BindingManagerPrivate::releaseWrapper(void* cptr) @@ -245,14 +249,32 @@ void BindingManager::invalidateWrapper(SbkBaseWrapper* wrapper) { if (!wrapper || ((PyObject*)wrapper == Py_None) || !SbkBaseWrapper_validCppObject(wrapper)) return; + + // skip this if the object is a wrapper class and this is not a destructor call + if (SbkBaseWrapper_containsCppWrapper(wrapper) && !m_d->destroying) { + ParentInfo* pInfo = wrapper->parentInfo; + // this meaning the object has a extra ref and we will remove this now + if (pInfo && pInfo->hasWrapperRef) { + delete pInfo; + wrapper->parentInfo = 0; + Py_XDECREF((PyObject*) wrapper); + } + return; + } + SbkBaseWrapper_setValidCppObject(wrapper, false); SbkBaseWrapper_setOwnership(wrapper, false); + // If it is a parent invalidate all children. if (SbkBaseWrapper_hasParentInfo(wrapper)) { ChildrenList::iterator it = wrapper->parentInfo->children.begin(); + bool parentDestroying = m_d->destroying; + m_d->destroying = false; for (; it != wrapper->parentInfo->children.end(); ++it) invalidateWrapper(*it); + m_d->destroying = parentDestroying; } + releaseWrapper(reinterpret_cast<PyObject*>(wrapper)); } @@ -263,6 +285,24 @@ void BindingManager::invalidateWrapper(const void* cptr) invalidateWrapper(iter->second); } +void BindingManager::destroyWrapper(const void* cptr) +{ + WrapperMap::iterator iter = m_d->wrapperMapper.find(cptr); + if (iter != m_d->wrapperMapper.end()) { + m_d->destroying = true; + invalidateWrapper(iter->second); + m_d->destroying = false; + } +} + +void BindingManager::destroyWrapper(SbkBaseWrapper* wrapper) +{ + m_d->destroying = true; + invalidateWrapper(wrapper); + m_d->destroying = false; +} + + void BindingManager::transferOwnershipToCpp(SbkBaseWrapper* wrapper) { if (wrapper->parentInfo) diff --git a/libshiboken/bindingmanager.h b/libshiboken/bindingmanager.h index d6985ccc7..2f486829f 100644 --- a/libshiboken/bindingmanager.h +++ b/libshiboken/bindingmanager.h @@ -64,6 +64,10 @@ public: void addClassInheritance(SbkBaseWrapperType* parent, SbkBaseWrapperType* child); SbkBaseWrapperType* resolveType(void* cptr, SbkBaseWrapperType* type); + + /// Called by wrapper destructor + void destroyWrapper(const void* cptr); + void destroyWrapper(SbkBaseWrapper* wrapper); private: ~BindingManager(); // disable copy |