aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6
diff options
context:
space:
mode:
authorFriedemann Kleint <[email protected]>2025-03-20 08:38:20 +0100
committerFriedemann Kleint <[email protected]>2025-05-22 15:34:18 +0200
commiteeacd90bdb71cebcdfb8d285254d7e42ddc4ff79 (patch)
treebe4a9fd0f99e7249c696afa5623ce3df4b3c880b /sources/shiboken6
parent5587fe5f0a1179de1402440789c34ff87788abfa (diff)
Speed up invocation of overridden functions
Cache the function found (extracted from the callable) instead of doing lookups and MRO search each time. Use Py_None (unreferenced) to indicate the method is not overridden. Reconstruct the callable from the function. Move the duckpunching check before the cache to avoid reference issues. Achieves a speedup of roughly 3.8->2.6s (33%). Task-number: PYSIDE-2916 Change-Id: I6deec60d14ed7030284e0e02249ea96df49e5740 Reviewed-by: Cristian Maureira-Fredes <[email protected]>
Diffstat (limited to 'sources/shiboken6')
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp2
-rw-r--r--sources/shiboken6/generator/shiboken/headergenerator.cpp6
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.cpp76
-rw-r--r--sources/shiboken6/libshiboken/basewrapper.h5
-rw-r--r--sources/shiboken6/libshiboken/bindingmanager.cpp11
5 files changed, 60 insertions, 40 deletions
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index 21e167b53..539094075 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -997,7 +997,7 @@ void CppGenerator::writeCacheResetNative(TextStream &s, const GeneratorContext &
{
s << "void " << classContext.wrapperName()
<< "::resetPyMethodCache()\n{\n" << indent
- << "std::fill_n(m_PyMethodCache, sizeof(m_PyMethodCache) / sizeof(m_PyMethodCache[0]), false);\n"
+ << "std::fill(m_PyMethodCache.begin(), m_PyMethodCache.end(), nullptr);\n"
<< outdent << "}\n\n";
}
diff --git a/sources/shiboken6/generator/shiboken/headergenerator.cpp b/sources/shiboken6/generator/shiboken/headergenerator.cpp
index 965d80dad..7616fa5c3 100644
--- a/sources/shiboken6/generator/shiboken/headergenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/headergenerator.cpp
@@ -185,6 +185,7 @@ void HeaderGenerator::writeWrapperClass(TextStream &s,
for( const auto &includeGroup : includeGroups)
s << includeGroup;
}
+ s << "#include <sbkpython.h>\n\n#include <array>\n";
s << "namespace Shiboken { class AutoDecRef; class GilState; }\n\n";
@@ -288,9 +289,10 @@ void *qt_metacast(const char *_clname) override;
}
if (needsMethodCache) {
- s << "mutable bool m_PyMethodCache[" << maxOverrides << "] = {false";
+ s << "mutable std::array<PyObject *, " << maxOverrides
+ << "> m_PyMethodCache = {nullptr";
for (int i = 1; i < maxOverrides; ++i)
- s << ", false";
+ s << ", nullptr";
s << "};\n";
}
diff --git a/sources/shiboken6/libshiboken/basewrapper.cpp b/sources/shiboken6/libshiboken/basewrapper.cpp
index 3e26b4605..039cd3085 100644
--- a/sources/shiboken6/libshiboken/basewrapper.cpp
+++ b/sources/shiboken6/libshiboken/basewrapper.cpp
@@ -21,6 +21,7 @@
#include "voidptr.h"
#include <algorithm>
+#include <cctype>
#include <cstddef>
#include <cstring>
#include <iostream>
@@ -786,32 +787,57 @@ static PyObject *overrideMethodName(PyObject *pySelf, const char *methodName,
// The virtual function call
PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject,
Shiboken::GilState &gil, const char *funcName,
- bool &resultCache, PyObject **nameCache)
-{
- PyObject *pyOverride{};
- if (!resultCache) {
- gil.acquire();
- auto &bindingManager = Shiboken::BindingManager::instance();
- SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject);
- // The refcount can be 0 if the object is dieing and someone called
- // a virtual method from the destructor
- if (wrapper == nullptr)
- return nullptr;
- auto *pySelf = reinterpret_cast<PyObject *>(wrapper);
- if (Py_REFCNT(pySelf) == 0)
- return nullptr;
- PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache);
- pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName);
- if (pyOverride == nullptr) {
- resultCache = true;
- gil.release();
- } else if (Shiboken::Errors::occurred() != nullptr) {
- // Give up.
- Py_XDECREF(pyOverride);
- pyOverride = nullptr;
- }
+ PyObject *&resultCache, PyObject **nameCache)
+{
+ if (Py_IsInitialized() == 0 || resultCache == Py_None)
+ return nullptr; // Bail out, execute C++ call (wrappers may outlive Python).
+
+ auto &bindingManager = Shiboken::BindingManager::instance();
+ SbkObject *wrapper = bindingManager.retrieveWrapper(voidThis, typeObject);
+ // The refcount can be 0 if the object is dieing and someone called
+ // a virtual method from the destructor
+ if (wrapper == nullptr)
+ return nullptr;
+ auto *pySelf = reinterpret_cast<PyObject *>(wrapper);
+ if (Py_REFCNT(pySelf) == 0)
+ return nullptr;
+
+ gil.acquire();
+
+ if (resultCache != nullptr) // recreate the callable from function/self
+ return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr);
+
+ PyObject *pyMethodName = overrideMethodName(pySelf, funcName, nameCache);
+ auto *wrapper_dict = SbkObject_GetDict_NoRef(pySelf);
+
+ // Note: This special case was implemented for duck-punching, which happens
+ // in the instance dict. It does not work with properties.
+ // This is not cached to avoid leaking. FIXME PYSIDE 7: Remove (PYSIDE-2916)?
+ if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
+ Py_INCREF(method);
+ return method;
+ }
+
+ auto *pyOverride = Shiboken::BindingManager::getOverride(wrapper, pyMethodName);
+ if (pyOverride == nullptr) {
+ resultCache = Py_None;
+ Py_INCREF(resultCache);
+ gil.release();
+ return nullptr; // No override, execute C++ call
}
- return pyOverride;
+
+ if (Shiboken::Errors::occurred() != nullptr) {
+ // Give up.
+ Py_XDECREF(pyOverride);
+ resultCache = Py_None;
+ Py_INCREF(resultCache);
+ gil.release();
+ return nullptr; // // Give up.
+ }
+
+ resultCache = pyOverride;
+ // recreate the callable from function/self
+ return PepExt_Type_CallDescrGet(resultCache, pySelf, nullptr);
}
namespace
diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
index 9eea89540..426298bcf 100644
--- a/sources/shiboken6/libshiboken/basewrapper.h
+++ b/sources/shiboken6/libshiboken/basewrapper.h
@@ -123,9 +123,8 @@ LIBSHIBOKEN_API PyObject *Sbk_ReturnFromPython_Self(PyObject *self);
} // extern "C"
LIBSHIBOKEN_API PyObject *Sbk_GetPyOverride(const void *voidThis, PyTypeObject *typeObject,
- Shiboken::GilState &gil,
- const char *funcName, bool &resultCache,
- PyObject **nameCache);
+ Shiboken::GilState &gil, const char *funcName,
+ PyObject *&resultCache, PyObject **nameCache);
namespace Shiboken
{
diff --git a/sources/shiboken6/libshiboken/bindingmanager.cpp b/sources/shiboken6/libshiboken/bindingmanager.cpp
index c8874553f..ca509aefd 100644
--- a/sources/shiboken6/libshiboken/bindingmanager.cpp
+++ b/sources/shiboken6/libshiboken/bindingmanager.cpp
@@ -369,13 +369,6 @@ SbkObject *BindingManager::retrieveWrapper(const void *cptr, PyTypeObject *typeO
PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName)
{
auto *obWrapper = reinterpret_cast<PyObject *>(wrapper);
- auto *wrapper_dict = SbkObject_GetDict_NoRef(obWrapper);
- if (PyObject *method = PyDict_GetItem(wrapper_dict, pyMethodName)) {
- // Note: This special case was implemented for duck-punching, which happens
- // in the instance dict. It does not work with properties.
- Py_INCREF(method);
- return method;
- }
Shiboken::AutoDecRef method(PyObject_GetAttr(obWrapper, pyMethodName));
if (method.isNull())
@@ -413,13 +406,13 @@ PyObject *BindingManager::getOverride(SbkObject *wrapper, PyObject *pyMethodName
if (PyObject *defaultMethod = PyDict_GetItem(parentDict.object(), pyMethodName)) {
defaultFound = true;
if (function != defaultMethod)
- return method.release();
+ return function;
}
}
}
// PYSIDE-2255: If no default method was found, use the method.
if (!defaultFound)
- return method.release();
+ return function;
return nullptr;
}