aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/generator/shiboken/cppgenerator.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2022-06-23 15:00:24 +0200
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2022-10-27 21:14:41 +0200
commitcef14671536d23b45661cdb203c8da50aed149f1 (patch)
treed39123cf4bc7466b5633b80835b2511801c0849d /sources/shiboken6/generator/shiboken/cppgenerator.cpp
parent5055eface884271590464284d23ad55f117d0a5d (diff)
shiboken6: Use vector call API for overridden virtual methods
Python 3.9 introduced more efficient call functions which use an array of PyObject * instead of a PyTuple (PyObject_Vectorcall) or use no args at all (PyObject_CallNoArgs). Generate #ifdefed code to use them. [ChangeLog][shiboken6] shiboken6 now generates new call functions PyObject_Vectorcall() or PyObject_CallNoArgs() for overridden virtual methods for newer Python versions. Change-Id: I952377183fbc11d792cd77fc6e5ee5f7e4accb23 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Christian Tismer <tismer@stackless.com>
Diffstat (limited to 'sources/shiboken6/generator/shiboken/cppgenerator.cpp')
-rw-r--r--sources/shiboken6/generator/shiboken/cppgenerator.cpp80
1 files changed, 80 insertions, 0 deletions
diff --git a/sources/shiboken6/generator/shiboken/cppgenerator.cpp b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
index f4ea51c7b..68e7f0028 100644
--- a/sources/shiboken6/generator/shiboken/cppgenerator.cpp
+++ b/sources/shiboken6/generator/shiboken/cppgenerator.cpp
@@ -1304,6 +1304,37 @@ QPair<QString, QChar> CppGenerator::virtualMethodNativeArg(const AbstractMetaFun
return {ac.toString(), u'N'};
}
+static const char PYTHON_ARGS_ARRAY[] = "pyArgArray";
+
+void CppGenerator::writeVirtualMethodNativeVectorCallArgs(TextStream &s,
+ const AbstractMetaFunctionCPtr &func,
+ const AbstractMetaArgumentList &arguments,
+ const QList<int> &invalidateArgs) const
+{
+ Q_ASSERT(!arguments.isEmpty());
+ s << "PyObject *" << PYTHON_ARGS_ARRAY <<'[' << arguments.size() << "] = {\n" << indent;
+ const qsizetype last = arguments.size() - 1;
+ for (qsizetype i = 0; i <= last; ++i) {
+ const AbstractMetaArgument &arg = arguments.at(i);
+ if (func->hasConversionRule(TypeSystem::TargetLangCode, arg.argumentIndex() + 1)) {
+ s << arg.name() + CONV_RULE_OUT_VAR_SUFFIX;
+ } else {
+ writeToPythonConversion(s, arg.type(), func->ownerClass(), arg.name());
+ }
+ if (i < last)
+ s << ',';
+ s << '\n';
+ }
+ s << outdent << "};\n";
+
+ if (!invalidateArgs.isEmpty())
+ s << '\n';
+ for (int index : invalidateArgs) {
+ s << "const bool invalidateArg" << index << " = " << PYTHON_ARGS_ARRAY <<
+ '[' << index - 1 << "]->ob_refcnt == 1;\n";
+ }
+}
+
void CppGenerator::writeVirtualMethodNativeArgs(TextStream &s,
const AbstractMetaFunctionCPtr &func,
const AbstractMetaArgumentList &arguments,
@@ -1337,6 +1368,16 @@ static bool isArgumentNotRemoved(const AbstractMetaArgument &a)
return !a.isModifiedRemoved();
}
+// PyObject_Vectorcall(): since 3.9
+static const char vectorCallCondition[] =
+ "#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x03090000\n";
+
+// PyObject_CallNoArgs(): since 3.9, stable API since 3.10
+static const char noArgsCallCondition[] =
+ "#if (defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030A0000) || (!defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x03090000)\n";
+static const char inverseNoArgsCallCondition[] =
+ "#if (defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030A0000) || (!defined(Py_LIMITED_API) && PY_VERSION_HEX < 0x03090000)\n";
+
void CppGenerator::writeVirtualMethodNative(TextStream &s,
const AbstractMetaFunctionCPtr &func,
int cacheIndex) const
@@ -1449,7 +1490,27 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
s << sbkUnusedVariableCast(it->name());
}
arguments.erase(removedEnd, arguments.end());
+
+ // FIXME PYSIDE-7: new functions PyObject_Vectorcall() (since 3.9) and
+ // PyObject_CallNoArgs() (since 3.9, stable API since 3.10) might have
+ // become part of the stable API?
+
+ // Code snips might expect the args tuple, don't generate new code
+ const bool generateNewCall = snips.isEmpty();
+ const qsizetype argCount = arguments.size();
+ const char *newCallCondition = argCount == 0 ? noArgsCallCondition : vectorCallCondition;
+ if (generateNewCall) {
+ if (argCount > 0) {
+ s << newCallCondition;
+ writeVirtualMethodNativeVectorCallArgs(s, func, arguments, invalidateArgs);
+ s << "#else\n";
+ } else {
+ s << inverseNoArgsCallCondition;
+ }
+ }
writeVirtualMethodNativeArgs(s, func, arguments, invalidateArgs);
+ if (generateNewCall)
+ s << "#endif\n";
s << '\n';
if (!snips.isEmpty()) {
@@ -1465,6 +1526,23 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
qsizetype returnIndirections = 0;
if (!func->injectedCodeCallsPythonOverride()) {
+ if (generateNewCall) {
+ s << newCallCondition << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << '(';
+ if (argCount > 0) {
+ s << "PyObject_Vectorcall(" << PYTHON_OVERRIDE_VAR << ", "
+ << PYTHON_ARGS_ARRAY << ", " << argCount << ", nullptr));\n";
+ for (int argIndex : qAsConst(invalidateArgs)) {
+ s << "if (invalidateArg" << argIndex << ")\n" << indent
+ << "Shiboken::Object::invalidate(" << PYTHON_ARGS_ARRAY
+ << '[' << (argIndex - 1) << "]);\n" << outdent;
+ }
+ for (qsizetype i = 0, size = arguments.size(); i < size; ++i)
+ s << "Py_DECREF(" << PYTHON_ARGS_ARRAY << '[' << i << "]);\n";
+ } else {
+ s << "PyObject_CallNoArgs(" << PYTHON_OVERRIDE_VAR << "));\n";
+ }
+ s << "#else\n";
+ }
s << "Shiboken::AutoDecRef " << PYTHON_RETURN_VAR << "(PyObject_Call("
<< PYTHON_OVERRIDE_VAR << ", " << PYTHON_ARGS << ", nullptr));\n";
@@ -1473,6 +1551,8 @@ void CppGenerator::writeVirtualMethodNative(TextStream &s,
<< "Shiboken::Object::invalidate(PyTuple_GET_ITEM(" << PYTHON_ARGS
<< ", " << (argIndex - 1) << "));\n" << outdent;
}
+ if (generateNewCall)
+ s << "#endif\n";
s << "if (" << PYTHON_RETURN_VAR << ".isNull()) {\n" << indent
<< "// An error happened in python code!\n"