diff options
Diffstat (limited to 'sources/shiboken2/libshiboken/bindingmanager.cpp')
-rw-r--r-- | sources/shiboken2/libshiboken/bindingmanager.cpp | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/sources/shiboken2/libshiboken/bindingmanager.cpp b/sources/shiboken2/libshiboken/bindingmanager.cpp deleted file mode 100644 index 725150e87..000000000 --- a/sources/shiboken2/libshiboken/bindingmanager.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt for Python. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "basewrapper.h" -#include "basewrapper_p.h" -#include "bindingmanager.h" -#include "sbkdbg.h" -#include "gilstate.h" -#include "sbkstring.h" -#include "debugfreehook.h" - -#include <cstddef> -#include <fstream> -#include <unordered_map> - -namespace Shiboken -{ - -using WrapperMap = std::unordered_map<const void *, SbkObject *>; - -class Graph -{ -public: - using NodeList = std::vector<SbkObjectType *>; - using Edges = std::unordered_map<SbkObjectType *, NodeList>; - - Edges m_edges; - - Graph() = default; - - void addEdge(SbkObjectType *from, SbkObjectType *to) - { - m_edges[from].push_back(to); - } - -#ifndef NDEBUG - void dumpDotGraph() - { - std::ofstream file("/tmp/shiboken_graph.dot"); - - file << "digraph D {\n"; - - for (auto i = m_edges.begin(), end = m_edges.end(); i != end; ++i) { - auto node1 = reinterpret_cast<const PyTypeObject *>(i->first); - const NodeList &nodeList = i->second; - for (const SbkObjectType *o : nodeList) { - auto node2 = reinterpret_cast<const PyTypeObject *>(o); - file << '"' << node2->tp_name << "\" -> \"" - << node1->tp_name << "\"\n"; - } - } - file << "}\n"; - } -#endif - - SbkObjectType *identifyType(void **cptr, SbkObjectType *type, SbkObjectType *baseType) const - { - auto edgesIt = m_edges.find(type); - if (edgesIt != m_edges.end()) { - const NodeList &adjNodes = m_edges.find(type)->second; - for (SbkObjectType *node : adjNodes) { - SbkObjectType *newType = identifyType(cptr, node, baseType); - if (newType) - return newType; - } - } - void *typeFound = nullptr; - if (PepType_SOTP(type) && PepType_SOTP(type)->type_discovery) { - typeFound = PepType_SOTP(type)->type_discovery(*cptr, baseType); - } - if (typeFound) { - // This "typeFound != type" is needed for backwards compatibility with old modules using a newer version of - // libshiboken because old versions of type_discovery function used to return a SbkObjectType *instead of - // a possible variation of the C++ instance pointer (*cptr). - if (typeFound != type) - *cptr = typeFound; - return type; - } - return nullptr; - } -}; - - -#ifndef NDEBUG -static void showWrapperMap(const WrapperMap &wrapperMap) -{ - if (Py_VerboseFlag > 0) { - fprintf(stderr, "-------------------------------\n"); - fprintf(stderr, "WrapperMap: %p (size: %d)\n", &wrapperMap, (int) wrapperMap.size()); - for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) { - const SbkObject *sbkObj = it->second; - fprintf(stderr, "key: %p, value: %p (%s, refcnt: %d)\n", it->first, - static_cast<const void *>(sbkObj), - (Py_TYPE(sbkObj))->tp_name, - int(reinterpret_cast<const PyObject *>(sbkObj)->ob_refcnt)); - } - fprintf(stderr, "-------------------------------\n"); - } -} -#endif - -struct BindingManager::BindingManagerPrivate { - using DestructorEntries = std::vector<DestructorEntry>; - - WrapperMap wrapperMapper; - Graph classHierarchy; - DestructorEntries deleteInMainThread; - bool destroying; - - BindingManagerPrivate() : destroying(false) {} - bool releaseWrapper(void *cptr, SbkObject *wrapper); - void assignWrapper(SbkObject *wrapper, const void *cptr); - -}; - -bool BindingManager::BindingManagerPrivate::releaseWrapper(void *cptr, SbkObject *wrapper) -{ - // The wrapper argument is checked to ensure that the correct wrapper is released. - // Returns true if the correct wrapper is found and released. - // If wrapper argument is NULL, no such check is performed. - auto iter = wrapperMapper.find(cptr); - if (iter != wrapperMapper.end() && (wrapper == nullptr || iter->second == wrapper)) { - wrapperMapper.erase(iter); - return true; - } - return false; -} - -void BindingManager::BindingManagerPrivate::assignWrapper(SbkObject *wrapper, const void *cptr) -{ - assert(cptr); - auto iter = wrapperMapper.find(cptr); - if (iter == wrapperMapper.end()) - wrapperMapper.insert(std::make_pair(cptr, wrapper)); -} - -BindingManager::BindingManager() -{ - m_d = new BindingManager::BindingManagerPrivate; - -#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK - debugInstallFreeHook(); -#endif -} - -BindingManager::~BindingManager() -{ -#ifdef SHIBOKEN_INSTALL_FREE_DEBUG_HOOK - debugRemoveFreeHook(); -#endif -#ifndef NDEBUG - showWrapperMap(m_d->wrapperMapper); -#endif - /* Cleanup hanging references. We just invalidate them as when - * the BindingManager is being destroyed the interpreter is alredy - * shutting down. */ - if (Py_IsInitialized()) { // ensure the interpreter is still valid - while (!m_d->wrapperMapper.empty()) { - Object::destroy(m_d->wrapperMapper.begin()->second, const_cast<void *>(m_d->wrapperMapper.begin()->first)); - } - assert(m_d->wrapperMapper.empty()); - } - delete m_d; -} - -BindingManager &BindingManager::instance() { - static BindingManager singleton; - return singleton; -} - -bool BindingManager::hasWrapper(const void *cptr) -{ - return m_d->wrapperMapper.find(cptr) != m_d->wrapperMapper.end(); -} - -void BindingManager::registerWrapper(SbkObject *pyObj, void *cptr) -{ - auto instanceType = reinterpret_cast<SbkObjectType *>(Py_TYPE(pyObj)); - SbkObjectTypePrivate *d = PepType_SOTP(instanceType); - - if (!d) - return; - - if (d->mi_init && !d->mi_offsets) - d->mi_offsets = d->mi_init(cptr); - m_d->assignWrapper(pyObj, cptr); - if (d->mi_offsets) { - int *offset = d->mi_offsets; - while (*offset != -1) { - if (*offset > 0) - m_d->assignWrapper(pyObj, reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(cptr) + *offset)); - offset++; - } - } -} - -void BindingManager::releaseWrapper(SbkObject *sbkObj) -{ - auto sbkType = reinterpret_cast<SbkObjectType *>(Py_TYPE(sbkObj)); - SbkObjectTypePrivate *d = PepType_SOTP(sbkType); - int numBases = ((d && d->is_multicpp) ? getNumberOfCppBaseClasses(Py_TYPE(sbkObj)) : 1); - - void ** cptrs = reinterpret_cast<SbkObject *>(sbkObj)->d->cptr; - for (int i = 0; i < numBases; ++i) { - auto *cptr = reinterpret_cast<unsigned char *>(cptrs[i]); - m_d->releaseWrapper(cptr, sbkObj); - if (d && d->mi_offsets) { - int *offset = d->mi_offsets; - while (*offset != -1) { - if (*offset > 0) - m_d->releaseWrapper(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(cptr) + *offset), sbkObj); - offset++; - } - } - } - sbkObj->d->validCppObject = false; -} - -void BindingManager::runDeletionInMainThread() -{ - for (const DestructorEntry &e : m_d->deleteInMainThread) - e.destructor(e.cppInstance); - m_d->deleteInMainThread.clear(); -} - -void BindingManager::addToDeletionInMainThread(const DestructorEntry &e) -{ - m_d->deleteInMainThread.push_back(e); -} - -SbkObject *BindingManager::retrieveWrapper(const void *cptr) -{ - auto iter = m_d->wrapperMapper.find(cptr); - if (iter == m_d->wrapperMapper.end()) - return nullptr; - return iter->second; -} - -PyObject *BindingManager::getOverride(const void *cptr, const char *methodName) -{ - SbkObject *wrapper = retrieveWrapper(cptr); - // The refcount can be 0 if the object is dieing and someone called - // a virtual method from the destructor - if (!wrapper || reinterpret_cast<const PyObject *>(wrapper)->ob_refcnt == 0) - return nullptr; - - if (wrapper->ob_dict) { - PyObject *method = PyDict_GetItemString(wrapper->ob_dict, methodName); - if (method) { - Py_INCREF(reinterpret_cast<PyObject *>(method)); - return method; - } - } - - PyObject *pyMethodName = Shiboken::String::fromCString(methodName); - PyObject *method = PyObject_GetAttr(reinterpret_cast<PyObject *>(wrapper), pyMethodName); - - if (method && PyMethod_Check(method) - && PyMethod_GET_SELF(method) == reinterpret_cast<PyObject *>(wrapper)) { - PyObject *defaultMethod; - PyObject *mro = Py_TYPE(wrapper)->tp_mro; - - // The first class in the mro (index 0) is the class being checked and it should not be tested. - // The last class in the mro (size - 1) is the base Python object class which should not be tested also. - for (int i = 1; i < PyTuple_GET_SIZE(mro) - 1; i++) { - auto *parent = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, i)); - if (parent->tp_dict) { - defaultMethod = PyDict_GetItem(parent->tp_dict, pyMethodName); - if (defaultMethod && PyMethod_GET_FUNCTION(method) != defaultMethod) { - Py_DECREF(pyMethodName); - return method; - } - } - } - } - - Py_XDECREF(method); - Py_DECREF(pyMethodName); - return nullptr; -} - -void BindingManager::addClassInheritance(SbkObjectType *parent, SbkObjectType *child) -{ - m_d->classHierarchy.addEdge(parent, child); -} - -SbkObjectType *BindingManager::resolveType(void *cptr, SbkObjectType *type) -{ - return resolveType(&cptr, type); -} - -SbkObjectType *BindingManager::resolveType(void **cptr, SbkObjectType *type) -{ - SbkObjectType *identifiedType = m_d->classHierarchy.identifyType(cptr, type, type); - return identifiedType ? identifiedType : type; -} - -std::set<PyObject *> BindingManager::getAllPyObjects() -{ - std::set<PyObject *> pyObjects; - const WrapperMap &wrappersMap = m_d->wrapperMapper; - auto it = wrappersMap.begin(); - for (; it != wrappersMap.end(); ++it) - pyObjects.insert(reinterpret_cast<PyObject *>(it->second)); - - return pyObjects; -} - -void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data) -{ - WrapperMap copy = m_d->wrapperMapper; - for (auto it = copy.begin(); it != copy.end(); ++it) { - if (hasWrapper(it->first)) - visitor(it->second, data); - } -} - -} // namespace Shiboken - |