aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/bindingmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/bindingmanager.cpp')
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp217
1 files changed, 152 insertions, 65 deletions
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index a0acc4e4b..83c927ae5 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -7,6 +7,7 @@
#include "bindingmanager.h"
#include "gilstate.h"
#include "helper.h"
+#include "sbkmodule.h"
#include "sbkstring.h"
#include "sbkstaticstrings.h"
#include "sbkfeature_base.h"
@@ -15,94 +16,152 @@
#include <cstddef>
#include <cstring>
#include <fstream>
+#include <iostream>
#include <mutex>
+#include <string_view>
#include <unordered_map>
+#include <unordered_set>
+
+// GraphNode for the dependency graph. It keeps a pointer to
+// the TypeInitStruct to be able to lazily create the type and hashes
+// by the full type name.
+struct GraphNode
+{
+ explicit GraphNode(Shiboken::Module::TypeInitStruct *i) : name(i->fullName), initStruct(i) {}
+ explicit GraphNode(const char *n) : name(n), initStruct(nullptr) {} // Only for searching
+
+ std::string_view name;
+ Shiboken::Module::TypeInitStruct *initStruct;
+
+ friend bool operator==(const GraphNode &n1, const GraphNode &n2) { return n1.name == n2.name; }
+ friend bool operator!=(const GraphNode &n1, const GraphNode &n2) { return n1.name != n2.name; }
+};
+
+template <>
+struct std::hash<GraphNode> {
+ size_t operator()(const GraphNode &n) const noexcept
+ {
+ return std::hash<std::string_view>{}(n.name);
+ }
+};
namespace Shiboken
{
using WrapperMap = std::unordered_map<const void *, SbkObject *>;
-class Graph
+template <class NodeType>
+class BaseGraph
{
public:
- using NodeList = std::vector<PyTypeObject *>;
- using Edges = std::unordered_map<PyTypeObject *, NodeList>;
+ using NodeList = std::vector<NodeType>;
+ using NodeSet = std::unordered_set<NodeType>;
+
+ using Edges = std::unordered_map<NodeType, NodeList>;
Edges m_edges;
- Graph() = default;
+ BaseGraph() = default;
- void addEdge(PyTypeObject *from, PyTypeObject *to)
+ void addEdge(NodeType from, NodeType to)
{
m_edges[from].push_back(to);
}
-#ifndef NDEBUG
- void dumpDotGraph() const
+ NodeSet nodeSet() const
{
- std::ofstream file("/tmp/shiboken_graph.dot");
-
- file << "digraph D {\n";
-
+ NodeSet result;
for (const auto &p : m_edges) {
- auto *node1 = p.first;
- const NodeList &nodeList = p.second;
- for (const PyTypeObject *o : nodeList) {
- auto *node2 = o;
- file << '"' << node2->tp_name << "\" -> \""
- << node1->tp_name << "\"\n";
- }
+ result.insert(p.first);
+ for (const auto node2 : p.second)
+ result.insert(node2);
}
- file << "}\n";
+ return result;
}
-#endif
+};
- PyTypeObject *identifyType(void **cptr, PyTypeObject *type, PyTypeObject *baseType) const
+class Graph : public BaseGraph<GraphNode>
+{
+public:
+ using TypeCptrPair = BindingManager::TypeCptrPair;
+
+ TypeCptrPair identifyType(void *cptr, PyTypeObject *type, PyTypeObject *baseType) const
{
- auto edgesIt = m_edges.find(type);
- if (edgesIt != m_edges.end()) {
- const NodeList &adjNodes = m_edges.find(type)->second;
- for (PyTypeObject *node : adjNodes) {
- PyTypeObject *newType = identifyType(cptr, node, baseType);
- if (newType)
- return newType;
- }
- }
- void *typeFound = nullptr;
- auto *sotp = PepType_SOTP(type);
- if (sotp->type_discovery)
- typeFound = sotp->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 PyTypeObject *instead of
- // a possible variation of the C++ instance pointer (*cptr).
- if (typeFound != type)
- *cptr = typeFound;
- return type;
- }
- return nullptr;
+ return identifyType(cptr, GraphNode(type->tp_name), type, baseType);
}
-};
+ bool dumpTypeGraph(const char *fileName) const;
-#ifndef NDEBUG
-static void showWrapperMap(const WrapperMap &wrapperMap)
+private:
+ TypeCptrPair identifyType(void *cptr, const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const;
+};
+
+Graph::TypeCptrPair Graph::identifyType(void *cptr,
+ const GraphNode &typeNode, PyTypeObject *type,
+ PyTypeObject *baseType) const
{
- if (Shiboken::pyVerbose() > 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(Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj))));
+ assert(typeNode.initStruct != nullptr || type != nullptr);
+ auto edgesIt = m_edges.find(typeNode);
+ if (edgesIt != m_edges.end()) {
+ const NodeList &adjNodes = edgesIt->second;
+ for (const auto &node : adjNodes) {
+ auto newType = identifyType(cptr, node, nullptr, baseType);
+ if (newType.first != nullptr)
+ return newType;
}
- fprintf(stderr, "-------------------------------\n");
}
+
+ if (type == nullptr) {
+ if (typeNode.initStruct->type == nullptr) // Layzily create type
+ type = Shiboken::Module::get(*typeNode.initStruct);
+ else
+ type = typeNode.initStruct->type;
+ }
+
+ auto *sotp = PepType_SOTP(type);
+ if (sotp->type_discovery != nullptr) {
+ if (void *derivedCPtr = sotp->type_discovery(cptr, baseType))
+ return {type, derivedCPtr};
+ }
+ return {nullptr, nullptr};
+}
+
+static void formatDotNode(std::string_view name, std::ostream &file)
+{
+ auto lastDot = name.rfind('.');
+ file << " \"" << name << "\" [ label=";
+ if (lastDot != std::string::npos) {
+ file << '"' << name.substr(lastDot + 1) << "\" tooltip=\""
+ << name.substr(0, lastDot) << '"';
+ } else {
+ file << '"' << name << '"';
+ }
+ file << " ]\n";
+}
+
+bool Graph::dumpTypeGraph(const char *fileName) const
+{
+ std::ofstream file(fileName);
+ if (!file.good())
+ return false;
+
+ file << "digraph D {\n";
+
+ // Define nodes with short names
+ for (const auto &node : nodeSet())
+ formatDotNode(node.name, file);
+
+ // Write edges
+ for (const auto &p : m_edges) {
+ const auto &node1 = p.first;
+ const NodeList &nodeList = p.second;
+ for (const auto &node2 : nodeList)
+ file << " \"" << node2.name << "\" -> \"" << node1.name << "\"\n";
+ }
+ file << "}\n";
+ return true;
}
-#endif
struct BindingManager::BindingManagerPrivate {
using DestructorEntries = std::vector<DestructorEntry>;
@@ -115,9 +174,6 @@ struct BindingManager::BindingManagerPrivate {
std::recursive_mutex wrapperMapLock;
Graph classHierarchy;
DestructorEntries deleteInMainThread;
- bool destroying;
-
- BindingManagerPrivate() : destroying(false) {}
bool releaseWrapper(void *cptr, SbkObject *wrapper, const int *bases = nullptr);
bool releaseWrapperHelper(void *cptr, SbkObject *wrapper);
@@ -189,7 +245,8 @@ BindingManager::~BindingManager()
debugRemoveFreeHook();
#endif
#ifndef NDEBUG
- showWrapperMap(m_d->wrapperMapper);
+ if (Shiboken::pyVerbose() > 0)
+ dumpWrapperMap();
#endif
/* Cleanup hanging references. We just invalidate them as when
* the BindingManager is being destroyed the interpreter is alredy
@@ -363,15 +420,24 @@ PyObject *BindingManager::getOverride(const void *cptr,
return nullptr;
}
-void BindingManager::addClassInheritance(PyTypeObject *parent, PyTypeObject *child)
+void BindingManager::addClassInheritance(Module::TypeInitStruct *parent,
+ Module::TypeInitStruct *child)
+{
+ m_d->classHierarchy.addEdge(GraphNode(parent), GraphNode(child));
+}
+
+BindingManager::TypeCptrPair BindingManager::findDerivedType(void *cptr, PyTypeObject *type) const
{
- m_d->classHierarchy.addEdge(parent, child);
+ return m_d->classHierarchy.identifyType(cptr, type, type);
}
+// FIXME PYSIDE7: remove, just for compatibility
PyTypeObject *BindingManager::resolveType(void **cptr, PyTypeObject *type)
{
- PyTypeObject *identifiedType = m_d->classHierarchy.identifyType(cptr, type, type);
- return identifiedType ? identifiedType : type;
+ auto result = findDerivedType(*cptr, type);
+ if (result.second != nullptr)
+ *cptr = result.second;
+ return result.first != nullptr ? result.first : type;
}
std::set<PyObject *> BindingManager::getAllPyObjects()
@@ -395,6 +461,27 @@ void BindingManager::visitAllPyObjects(ObjectVisitor visitor, void *data)
}
}
+bool BindingManager::dumpTypeGraph(const char *fileName) const
+{
+ return m_d->classHierarchy.dumpTypeGraph(fileName);
+}
+
+void BindingManager::dumpWrapperMap()
+{
+ const auto &wrapperMap = m_d->wrapperMapper;
+ std::cerr << "-------------------------------\n"
+ << "WrapperMap size: " << wrapperMap.size() << " Types: "
+ << m_d->classHierarchy.nodeSet().size() << '\n';
+ for (auto it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
+ const SbkObject *sbkObj = it->second;
+ std::cerr << "key: " << it->first << ", value: "
+ << static_cast<const void *>(sbkObj) << " ("
+ << (Py_TYPE(sbkObj))->tp_name << ", refcnt: "
+ << Py_REFCNT(reinterpret_cast<const PyObject *>(sbkObj)) << ")\n";
+ }
+ std::cerr << "-------------------------------\n";
+}
+
static bool isPythonType(PyTypeObject *type)
{
// This is a type which should be called by multiple inheritance.