aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/libshiboken/pep384impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/libshiboken/pep384impl.cpp')
-rw-r--r--sources/shiboken6/libshiboken/pep384impl.cpp1294
1 files changed, 1294 insertions, 0 deletions
diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
new file mode 100644
index 000000000..2b04af857
--- /dev/null
+++ b/sources/shiboken6/libshiboken/pep384impl.cpp
@@ -0,0 +1,1294 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define PEP384_INTERN
+
+#include "sbkpython.h"
+#include "autodecref.h"
+#include "sbkstaticstrings.h"
+#include "sbkstaticstrings_p.h"
+#include "basewrapper.h"
+#include "basewrapper_p.h"
+#include "sbkenum.h"
+#include "voidptr.h"
+
+#include <cstdlib>
+#include <cstring>
+
+extern "C"
+{
+
+/*
+ * The documentation is located in `sources/pyside6/doc/developer/limited_api.rst`.
+
+ * Here is the verification code for PyTypeObject.
+ * We create a type object and check if its fields
+ * appear at the right offsets.
+ */
+#ifdef Py_LIMITED_API
+
+#define make_dummy_int(x) (x * sizeof(void *))
+#define make_dummy(x) (reinterpret_cast<void *>(make_dummy_int(x)))
+
+static PyObject *
+dummy_func(PyObject * /* self */, PyObject * /* args */)
+{
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef probe_methoddef[] = {
+ {"dummy", dummy_func, METH_NOARGS, nullptr},
+ {nullptr, nullptr, 0, nullptr}
+};
+
+static PyGetSetDef probe_getseters[] = {
+ {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
+};
+
+static PyMemberDef probe_members[] = {
+ {nullptr, 0, 0, 0, nullptr} /* Sentinel */
+};
+
+#define probe_tp_dealloc make_dummy(1)
+#define probe_tp_repr make_dummy(2)
+#define probe_tp_call make_dummy(3)
+#define probe_tp_getattro make_dummy(16)
+#define probe_tp_setattro make_dummy(17)
+#define probe_tp_str make_dummy(4)
+#define probe_tp_traverse make_dummy(5)
+#define probe_tp_clear make_dummy(6)
+#define probe_tp_iternext make_dummy(7)
+#define probe_tp_methods probe_methoddef
+#define probe_tp_members probe_members
+#define probe_tp_getset probe_getseters
+#define probe_tp_descr_get make_dummy(10)
+#define probe_tp_descr_set make_dummy(18)
+#define probe_tp_init make_dummy(11)
+#define probe_tp_alloc make_dummy(12)
+#define probe_tp_new make_dummy(13)
+#define probe_tp_free make_dummy(14)
+#define probe_tp_is_gc make_dummy(15)
+
+#define probe_tp_name "type.probe"
+#define probe_tp_basicsize make_dummy_int(42)
+
+static PyType_Slot typeprobe_slots[] = {
+ {Py_tp_dealloc, probe_tp_dealloc},
+ {Py_tp_repr, probe_tp_repr},
+ {Py_tp_call, probe_tp_call},
+ {Py_tp_getattro, probe_tp_getattro},
+ {Py_tp_setattro, probe_tp_setattro},
+ {Py_tp_str, probe_tp_str},
+ {Py_tp_traverse, probe_tp_traverse},
+ {Py_tp_clear, probe_tp_clear},
+ {Py_tp_iternext, probe_tp_iternext},
+ {Py_tp_methods, probe_tp_methods},
+ {Py_tp_members, probe_tp_members},
+ {Py_tp_getset, probe_tp_getset},
+ {Py_tp_descr_get, probe_tp_descr_get},
+ {Py_tp_descr_set, probe_tp_descr_set},
+ {Py_tp_init, probe_tp_init},
+ {Py_tp_alloc, probe_tp_alloc},
+ {Py_tp_new, probe_tp_new},
+ {Py_tp_free, probe_tp_free},
+ {Py_tp_is_gc, probe_tp_is_gc},
+ {0, nullptr}
+};
+static PyType_Spec typeprobe_spec = {
+ probe_tp_name,
+ probe_tp_basicsize,
+ 0,
+ Py_TPFLAGS_DEFAULT,
+ typeprobe_slots,
+};
+
+static void
+check_PyTypeObject_valid()
+{
+ auto *typetype = &PyType_Type;
+ auto *obtype = reinterpret_cast<PyObject *>(typetype);
+ auto *probe_tp_base_obj = PyObject_GetAttr(obtype, Shiboken::PyMagicName::base());
+ auto *probe_tp_base = reinterpret_cast<PyTypeObject *>(probe_tp_base_obj);
+ auto *probe_tp_bases = PyObject_GetAttr(obtype, Shiboken::PyMagicName::bases());
+ auto *checkObj = PyType_FromSpecWithBases(&typeprobe_spec, probe_tp_bases);
+ auto *check = reinterpret_cast<PyTypeObject *>(checkObj);
+ PyObject *w = PyObject_GetAttr(obtype, Shiboken::PyMagicName::weakrefoffset());
+ long probe_tp_weakrefoffset = PyLong_AsLong(w);
+ PyObject *d = PyObject_GetAttr(obtype, Shiboken::PyMagicName::dictoffset());
+ long probe_tp_dictoffset = PyLong_AsLong(d);
+ PyObject *probe_tp_mro = PyObject_GetAttr(obtype, Shiboken::PyMagicName::mro());
+ Shiboken::AutoDecRef tpDict(PepType_GetDict(check));
+ auto *checkDict = tpDict.object();
+ if (false
+ || strcmp(probe_tp_name, check->tp_name) != 0
+ || probe_tp_basicsize != check->tp_basicsize
+ || probe_tp_dealloc != check->tp_dealloc
+ || probe_tp_repr != check->tp_repr
+ || probe_tp_call != check->tp_call
+ || probe_tp_getattro != check->tp_getattro
+ || probe_tp_setattro != check->tp_setattro
+ || probe_tp_str != check->tp_str
+ || probe_tp_traverse != check->tp_traverse
+ || probe_tp_clear != check->tp_clear
+ || probe_tp_weakrefoffset != typetype->tp_weaklistoffset
+ || probe_tp_iternext != check->tp_iternext
+ || probe_tp_methods != check->tp_methods
+ || probe_tp_getset != check->tp_getset
+ || probe_tp_base != typetype->tp_base
+ || !PyDict_Check(checkDict)
+ || !PyDict_GetItemString(checkDict, "dummy")
+ || probe_tp_descr_get != check->tp_descr_get
+ || probe_tp_descr_set != check->tp_descr_set
+ || probe_tp_dictoffset != typetype->tp_dictoffset
+ || probe_tp_init != check->tp_init
+ || probe_tp_alloc != check->tp_alloc
+ || probe_tp_new != check->tp_new
+ || probe_tp_free != check->tp_free
+ || probe_tp_is_gc != check->tp_is_gc
+ || probe_tp_bases != typetype->tp_bases
+ || probe_tp_mro != typetype->tp_mro
+ || Py_TPFLAGS_DEFAULT != (check->tp_flags & Py_TPFLAGS_DEFAULT))
+ Py_FatalError("The structure of type objects has changed!");
+ Py_DECREF(checkObj);
+ Py_DECREF(probe_tp_base_obj);
+ Py_DECREF(w);
+ Py_DECREF(d);
+ Py_DECREF(probe_tp_bases);
+ Py_DECREF(probe_tp_mro);
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Additional for object.h / class properties
+ *
+ */
+#ifdef Py_LIMITED_API
+/*
+ * This implementation of `_PyType_Lookup` works for lookup in our classes.
+ * The implementation ignores all caching and versioning and is also
+ * less optimized. This is reduced from the Python implementation.
+ */
+
+/* Internal API to look for a name through the MRO, bypassing the method cache.
+ This returns a borrowed reference, and might set an exception.
+ 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */
+static PyObject *
+find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
+{
+ Py_ssize_t i, n;
+ PyObject *mro, *res, *base;
+
+ /* Look in tp_dict of types in MRO */
+ mro = type->tp_mro;
+
+ res = nullptr;
+ /* Keep a strong reference to mro because type->tp_mro can be replaced
+ during dict lookup, e.g. when comparing to non-string keys. */
+ Py_INCREF(mro);
+ assert(PyTuple_Check(mro));
+ n = PyTuple_GET_SIZE(mro);
+ for (i = 0; i < n; i++) {
+ base = PyTuple_GET_ITEM(mro, i);
+ assert(PyType_Check(base));
+ auto *type = reinterpret_cast<PyTypeObject *>(base);
+ Shiboken::AutoDecRef dict(PepType_GetDict(type));
+ assert(!dict.isNull() && PyDict_Check(dict.object()));
+ res = PyDict_GetItem(dict.object(), name);
+ if (res != nullptr)
+ break;
+ if (PyErr_Occurred()) {
+ *error = -1;
+ goto done;
+ }
+ }
+ *error = 0;
+done:
+ Py_DECREF(mro);
+ return res;
+}
+
+/* Internal API to look for a name through the MRO.
+ This returns a borrowed reference, and doesn't set an exception! */
+PyObject *
+_PepType_Lookup(PyTypeObject *type, PyObject *name)
+{
+ PyObject *res;
+ int error;
+
+ /* We may end up clearing live exceptions below, so make sure it's ours. */
+ assert(!PyErr_Occurred());
+
+ res = find_name_in_mro(type, name, &error);
+ /* Only put NULL results into cache if there was no error. */
+ if (error) {
+ /* It's not ideal to clear the error condition,
+ but this function is documented as not setting
+ an exception, and I don't want to change that.
+ E.g., when PyType_Ready() can't proceed, it won't
+ set the "ready" flag, so future attempts to ready
+ the same type will call it again -- hopefully
+ in a context that propagates the exception out.
+ */
+ if (error == -1) {
+ PyErr_Clear();
+ }
+ return nullptr;
+ }
+ return res;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for unicodeobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// structs and macros modelled after their equivalents in
+// cpython/Include/cpython/unicodeobject.h
+
+struct PepASCIIObject // since 3.12
+{
+ PyObject_HEAD
+ Py_ssize_t length; /* Number of code points in the string */
+ Py_hash_t hash; /* Hash value; -1 if not set */
+ struct {
+ unsigned int interned:2;
+ unsigned int kind:3;
+ unsigned int compact:1;
+ unsigned int ascii:1;
+ unsigned int ready:1;
+ unsigned int :24;
+ } state;
+};
+
+struct PepASCIIObject_311 : public PepASCIIObject
+{
+ wchar_t *wstr; /* wchar_t representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject // since 3.12
+{
+ PepASCIIObject _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+};
+
+struct PepCompactUnicodeObject_311 // since 3.12
+{
+ PepASCIIObject_311 _base;
+ Py_ssize_t utf8_length;
+ char *utf8; /* UTF-8 representation (null-terminated) */
+ Py_ssize_t wstr_length; /* Number of code points in wstr */
+};
+
+struct PepUnicodeObject // since 3.12
+{
+ PepCompactUnicodeObject _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+struct PepUnicodeObject_311
+{
+ PepCompactUnicodeObject_311 _base;
+ union {
+ void *any;
+ Py_UCS1 *latin1;
+ Py_UCS2 *ucs2;
+ Py_UCS4 *ucs4;
+ } data; /* Canonical, smallest-form Unicode buffer */
+};
+
+int _PepUnicode_KIND(PyObject *str)
+{
+ return reinterpret_cast<PepASCIIObject *>(str)->state.kind;
+}
+
+int _PepUnicode_IS_ASCII(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.ascii;
+}
+
+int _PepUnicode_IS_COMPACT(PyObject *str)
+{
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj->state.compact;
+}
+
+static void *_PepUnicode_ASCII_DATA(PyObject *str)
+{
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *asciiObj_311 = reinterpret_cast<PepASCIIObject_311 *>(str);
+ return asciiObj_311 + 1;
+ }
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ return asciiObj + 1;
+}
+
+static void *_PepUnicode_COMPACT_DATA(PyObject *str)
+{
+ if (_PepUnicode_IS_ASCII(str) != 0)
+ return _PepUnicode_ASCII_DATA(str);
+ if (_PepRuntimeVersion() < 0x030C00) {
+ auto *compactObj_311 = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ return compactObj_311 + 1;
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ return compactObj + 1;
+}
+
+static void *_PepUnicode_NONCOMPACT_DATA(PyObject *str)
+{
+ return _PepRuntimeVersion() < 0x030C00
+ ? reinterpret_cast<PepUnicodeObject_311 *>(str)->data.any
+ : reinterpret_cast<PepUnicodeObject *>(str)->data.any;
+}
+
+void *_PepUnicode_DATA(PyObject *str)
+{
+ return _PepUnicode_IS_COMPACT(str)
+ ? _PepUnicode_COMPACT_DATA(str) : _PepUnicode_NONCOMPACT_DATA(str);
+}
+
+// Fast path accessing UTF8 data without doing a conversion similar
+// to _PyUnicode_AsUTF8String
+static const char *utf8FastPath_311(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject_311 *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject_311 *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+static const char *utf8FastPath(PyObject *str)
+{
+ if (PyUnicode_GetLength(str) == 0)
+ return "";
+ auto *asciiObj = reinterpret_cast<PepASCIIObject *>(str);
+ if (asciiObj->state.kind != PepUnicode_1BYTE_KIND || asciiObj->state.compact == 0)
+ return nullptr; // Empirical: PyCompactUnicodeObject.utf8 is only valid for 1 byte
+ if (asciiObj->state.ascii) {
+ auto *data = asciiObj + 1;
+ return reinterpret_cast<const char *>(data);
+ }
+ auto *compactObj = reinterpret_cast<PepCompactUnicodeObject *>(str);
+ if (compactObj->utf8_length)
+ return compactObj->utf8;
+ return nullptr;
+}
+
+const char *_PepUnicode_AsString(PyObject *str)
+{
+ /*
+ * This function is the surrogate for PyUnicode_AsUTF8, which keeps the data
+ * in the unicode object as long as that object exists.
+ *
+ * The function does too much if not optimized by utf8, because it keeps the
+ * string alive, unconditionally.
+ * We should not rely on this behavior and think of PyUnicode_AsUTF8, only.
+ */
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+#define AT __FILE__ ":" TOSTRING(__LINE__)
+
+ if (const auto *utf8 = _PepRuntimeVersion() < 0x030C00
+ ? utf8FastPath_311(str) : utf8FastPath(str)) {
+ return utf8;
+ }
+
+ static PyObject *cstring_dict = nullptr;
+ if (cstring_dict == nullptr) {
+ cstring_dict = PyDict_New();
+ if (cstring_dict == nullptr)
+ Py_FatalError("Error in " AT);
+ }
+ PyObject *bytesStr = PyUnicode_AsEncodedString(str, "utf8", nullptr);
+ PyObject *entry = PyDict_GetItemWithError(cstring_dict, bytesStr);
+ if (entry == nullptr) {
+ int e = PyDict_SetItem(cstring_dict, bytesStr, bytesStr);
+ if (e != 0)
+ Py_FatalError("Error in " AT);
+ entry = bytesStr;
+ }
+ else
+ Py_DECREF(bytesStr);
+ return PyBytes_AsString(entry);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pydebug.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+static PyObject *sys_flags = nullptr;
+
+int
+Pep_GetFlag(const char *name)
+{
+ static int initialized = 0;
+ int ret = -1;
+
+ if (!initialized) {
+ sys_flags = PySys_GetObject("flags");
+ // func gives no error if nullptr is returned and does not incref.
+ Py_XINCREF(sys_flags);
+ initialized = 1;
+ }
+ if (sys_flags != nullptr) {
+ PyObject *ob_ret = PyObject_GetAttrString(sys_flags, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ }
+ return ret;
+}
+
+int
+Pep_GetVerboseFlag()
+{
+ static int initialized = 0;
+ static int verbose_flag = -1;
+
+ if (!initialized) {
+ verbose_flag = Pep_GetFlag("verbose");
+ if (verbose_flag != -1)
+ initialized = 1;
+ }
+ return verbose_flag;
+}
+#endif // Py_LIMITED_API
+
+// Support for pyerrors.h
+
+#if defined(Py_LIMITED_API) || PY_VERSION_HEX < 0x030C0000
+// Emulate PyErr_GetRaisedException() using the deprecated PyErr_Fetch()/PyErr_Store()
+PyObject *PepErr_GetRaisedException()
+{
+ PyObject *type{};
+ PyObject *value{};
+ PyObject *traceback{};
+ PyErr_Fetch(&type, &value, &traceback);
+ Py_XINCREF(value);
+ PyErr_Restore(type, value, traceback);
+ return value;
+}
+#endif // Limited or < 3.12
+
+/*****************************************************************************
+ *
+ * Support for code.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+int
+PepCode_Get(PepCodeObject *co, const char *name)
+{
+ PyObject *ob = reinterpret_cast<PyObject *>(co);
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+int PepCode_Check(PyObject *o)
+{
+ return o != nullptr && std::strcmp(Py_TYPE(o)->tp_name, "code") == 0 ? 1 : 0;
+}
+
+#endif // Py_LIMITED_API
+
+#if defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+PyObject *PepFunction_GetDefaults(PyObject *function)
+{
+ auto *ob_ret = PyObject_GetAttrString(function, "__defaults__");
+ Py_XDECREF(ob_ret); // returns borrowed ref
+ return ob_ret != Py_None ? ob_ret : nullptr;
+}
+
+#endif // defined(Py_LIMITED_API) || defined(PYPY_VERSION)
+
+/*****************************************************************************
+ *
+ * Support for datetime.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+datetime_struc *PyDateTimeAPI = nullptr;
+
+static PyTypeObject *dt_getCheck(const char *name)
+{
+ PyObject *op = PyObject_GetAttrString(PyDateTimeAPI->module, name);
+ if (op == nullptr) {
+ fprintf(stderr, "datetime.%s not found\n", name);
+ Py_FatalError("aborting");
+ }
+ return reinterpret_cast<PyTypeObject *>(op);
+}
+
+// init_DateTime is called earlier than our module init.
+// We use the provided PyDateTime_IMPORT machinery.
+datetime_struc *
+init_DateTime(void)
+{
+ static int initialized = 0;
+ if (!initialized) {
+ PyDateTimeAPI = (datetime_struc *)malloc(sizeof(datetime_struc));
+ if (PyDateTimeAPI == nullptr)
+ Py_FatalError("PyDateTimeAPI malloc error, aborting");
+ PyDateTimeAPI->module = PyImport_ImportModule("datetime");
+ if (PyDateTimeAPI->module == nullptr)
+ Py_FatalError("datetime module not found, aborting");
+ PyDateTimeAPI->DateType = dt_getCheck("date");
+ PyDateTimeAPI->DateTimeType = dt_getCheck("datetime");
+ PyDateTimeAPI->TimeType = dt_getCheck("time");
+ PyDateTimeAPI->DeltaType = dt_getCheck("timedelta");
+ PyDateTimeAPI->TZInfoType = dt_getCheck("tzinfo");
+ initialized = 1;
+ }
+ return PyDateTimeAPI;
+}
+
+int
+PyDateTime_Get(PyObject *ob, const char *name)
+{
+ PyObject *ob_ret;
+ int ret = -1;
+
+ ob_ret = PyObject_GetAttrString(ob, name);
+ if (ob_ret != nullptr) {
+ long long_ret = PyLong_AsLong(ob_ret);
+ Py_DECREF(ob_ret);
+ ret = (int) long_ret;
+ }
+ return ret;
+}
+
+PyObject *
+PyDate_FromDate(int year, int month, int day)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateType,
+ (char *)"(iii)", year, month, day);
+}
+
+PyObject *
+PyDateTime_FromDateAndTime(int year, int month, int day,
+ int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->DateTimeType,
+ (char *)"(iiiiiii)", year, month, day,
+ hour, min, sec, usec);
+}
+
+PyObject *
+PyTime_FromTime(int hour, int min, int sec, int usec)
+{
+ return PyObject_CallFunction((PyObject *)PyDateTimeAPI->TimeType,
+ (char *)"(iiii)", hour, min, sec, usec);
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for pythonrun.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+// Flags are ignored in these simple helpers.
+PyObject *
+PyRun_String(const char *str, int start, PyObject *globals, PyObject *locals)
+{
+ PyObject *code = Py_CompileString(str, "pyscript", start);
+ PyObject *ret = nullptr;
+
+ if (code != nullptr) {
+ ret = PyEval_EvalCode(code, globals, locals);
+ }
+ Py_XDECREF(code);
+ return ret;
+}
+
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for classobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepMethod_TypePtr = nullptr;
+
+static PyTypeObject *getMethodType(void)
+{
+ static const char prog[] =
+ "class _C:\n"
+ " def _m(self): pass\n"
+ "result = type(_C()._m)\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+// We have no access to PyMethod_New and must call types.MethodType, instead.
+PyObject *
+PyMethod_New(PyObject *func, PyObject *self)
+{
+ return PyObject_CallFunction((PyObject *)PepMethod_TypePtr,
+ (char *)"(OO)", func, self);
+}
+
+PyObject *
+PyMethod_Function(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::func());
+
+ // We have to return a borrowed reference.
+ Py_DECREF(ret);
+ return ret;
+}
+
+PyObject *
+PyMethod_Self(PyObject *im)
+{
+ PyObject *ret = PyObject_GetAttr(im, Shiboken::PyMagicName::self());
+
+ // We have to return a borrowed reference.
+ // If we don't obey that here, then we get a test error!
+ Py_DECREF(ret);
+ return ret;
+}
+#endif // Py_LIMITED_API
+
+/*****************************************************************************
+ *
+ * Support for funcobject.h
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PepFunction_Get(PyObject *ob, const char *name)
+{
+ PyObject *ret;
+
+ // We have to return a borrowed reference.
+ ret = PyObject_GetAttrString(ob, name);
+ Py_XDECREF(ret);
+ return ret;
+}
+
+// This became necessary after Windows was activated.
+
+PyTypeObject *PepFunction_TypePtr = nullptr;
+
+static PyTypeObject *getFunctionType(void)
+{
+ static const char prog[] =
+ "from types import FunctionType as result\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+#endif // Py_LIMITED_API || Python 2
+
+/*****************************************************************************
+ *
+ * Support for dictobject.h
+ *
+ */
+
+/*****************************************************************************
+ *
+ * Extra support for signature.cpp
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyTypeObject *PepStaticMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getStaticMethodType(void)
+{
+ static const char prog[] =
+ "result = type(str.__dict__['maketrans'])\n";
+ return reinterpret_cast<PyTypeObject *>(PepRun_GetResult(prog));
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *sm_callable;
+ PyObject *sm_dict;
+} staticmethod;
+
+PyObject *
+PyStaticMethod_New(PyObject *callable)
+{
+ staticmethod *sm = (staticmethod *)
+ PyType_GenericAlloc(PepStaticMethod_TypePtr, 0);
+ if (sm != nullptr) {
+ Py_INCREF(callable);
+ sm->sm_callable = callable;
+ }
+ return reinterpret_cast<PyObject *>(sm);
+}
+#endif // Py_LIMITED_API
+
+#ifdef PYPY_VERSION
+PyTypeObject *PepBuiltinMethod_TypePtr = nullptr;
+
+static PyTypeObject *
+getBuiltinMethodType(void)
+{
+ // PYSIDE-535: PyPy has a special builtin method that acts almost like PyCFunction.
+ //
+ // There is no public declaration for the "builtin method" type.
+ // We also cannot grep it with a Python script since the import is too early.
+ // Pick a demo "builtin method" by using the VoidPtr type.
+ // Create the equivalent of
+ // "from shiboken6.Shiboken import VoidPtr\n"
+ // "result = type(VoidPtr(0).toBytes)\n";
+ auto *pyVoidP = reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF());
+ Shiboken::AutoDecRef arg(Py_BuildValue("i", 0));
+ Shiboken::AutoDecRef inst(PyObject_CallFunctionObjArgs(pyVoidP, arg.object(), nullptr));
+ Shiboken::AutoDecRef meth(PyObject_GetAttrString(inst, "toBytes"));
+ auto *result = reinterpret_cast<PyTypeObject *>(PyObject_Type(meth));
+ return result;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Common newly needed functions
+ *
+ */
+
+// The introduction of heaptypes converted many type names to the
+// dotted form, since PyType_FromSpec uses it to compute the module
+// name. This function reverts this effect.
+const char *
+PepType_GetNameStr(PyTypeObject *type)
+{
+ const char *ret = type->tp_name;
+ const char *nodots = std::strrchr(ret, '.');
+ if (nodots)
+ ret = nodots + 1;
+ return ret;
+}
+
+// PYSIDE-2264: Find the _functools or functools module and retrieve the
+// partial function. This can be tampered with, check carefully.
+PyObject *
+Pep_GetPartialFunction(void)
+{
+ static bool initialized = false;
+ static PyObject *result{};
+ if (initialized) {
+ Py_INCREF(result);
+ return result;
+ }
+ auto *functools = PyImport_ImportModule("_functools");
+ if (!functools) {
+ PyErr_Clear();
+ functools = PyImport_ImportModule("functools");
+ }
+ if (!functools)
+ Py_FatalError("functools cannot be found");
+ result = PyObject_GetAttrString(functools, "partial");
+ if (!result || !PyCallable_Check(result))
+ Py_FatalError("partial not found or not a function");
+ initialized = true;
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Newly introduced convenience functions
+ *
+ */
+#ifdef Py_LIMITED_API
+
+PyObject *
+PyImport_GetModule(PyObject *name)
+{
+ PyObject *m;
+ PyObject *modules = PyImport_GetModuleDict();
+ if (modules == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
+ return NULL;
+ }
+ Py_INCREF(modules);
+ if (PyDict_CheckExact(modules)) {
+ m = PyDict_GetItemWithError(modules, name); /* borrowed */
+ Py_XINCREF(m);
+ }
+ else {
+ m = PyObject_GetItem(modules, name);
+ if (m == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_Clear();
+ }
+ }
+ Py_DECREF(modules);
+ return m;
+}
+
+#endif // Py_LIMITED_API
+
+// 2020-06-16: For simplicity of creating arbitrary things, this function
+// is now made public.
+
+PyObject *
+PepRun_GetResult(const char *command)
+{
+ /*
+ * Evaluate a string and return the variable `result`
+ */
+ PyObject *d, *v, *res;
+
+ d = PyDict_New();
+ if (d == nullptr
+ || PyDict_SetItem(d, Shiboken::PyMagicName::builtins(), PyEval_GetBuiltins()) < 0) {
+ return nullptr;
+ }
+ v = PyRun_String(command, Py_file_input, d, d);
+ res = v ? PyDict_GetItem(d, Shiboken::PyName::result()) : nullptr;
+ Py_XDECREF(v);
+ Py_DECREF(d);
+ return res;
+}
+
+PyTypeObject *PepType_Type_tp_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
+{
+ auto ret = PyType_Type.tp_new(metatype, args, kwds);
+ return reinterpret_cast<PyTypeObject *>(ret);
+}
+
+/*****************************************************************************
+ *
+ * Extra support for name mangling
+ *
+ */
+
+#ifdef Py_LIMITED_API
+// We keep these definitions local, because they don't work in Python 2.
+# define PyUnicode_GET_LENGTH(op) PyUnicode_GetLength((PyObject *)(op))
+# define PyUnicode_READ_CHAR(u, i) PyUnicode_ReadChar((PyObject *)(u), (i))
+#endif // Py_LIMITED_API
+
+PyObject *
+_Pep_PrivateMangle(PyObject *self, PyObject *name)
+{
+ /*
+ * Name mangling: __private becomes _classname__private.
+ * This function is modelled after _Py_Mangle, but is optimized
+ * a little for our purpose.
+ */
+ if (PyUnicode_READ_CHAR(name, 0) != '_' ||
+ PyUnicode_READ_CHAR(name, 1) != '_') {
+ Py_INCREF(name);
+ return name;
+ }
+ size_t nlen = PyUnicode_GET_LENGTH(name);
+ /* Don't mangle __id__ or names with dots. */
+ if ((PyUnicode_READ_CHAR(name, nlen-1) == '_' &&
+ PyUnicode_READ_CHAR(name, nlen-2) == '_') ||
+ PyUnicode_FindChar(name, '.', 0, nlen, 1) != -1) {
+ Py_INCREF(name);
+ return name;
+ }
+ Shiboken::AutoDecRef privateobj(PyObject_GetAttr(
+ reinterpret_cast<PyObject *>(Py_TYPE(self)), Shiboken::PyMagicName::name()));
+
+ // PYSIDE-1436: _Py_Mangle is no longer exposed; implement it always.
+ // The rest of this function is our own implementation of _Py_Mangle.
+ // Please compare the original function in compile.c .
+ size_t plen = PyUnicode_GET_LENGTH(privateobj.object());
+ /* Strip leading underscores from class name */
+ size_t ipriv = 0;
+ while (PyUnicode_READ_CHAR(privateobj.object(), ipriv) == '_')
+ ipriv++;
+ if (ipriv == plen) {
+ Py_INCREF(name);
+ return name; /* Don't mangle if class is just underscores */
+ }
+ plen -= ipriv;
+
+ if (plen + nlen >= PY_SSIZE_T_MAX - 1) {
+ PyErr_SetString(PyExc_OverflowError,
+ "private identifier too large to be mangled");
+ return nullptr;
+ }
+ size_t const amount = ipriv + 1 + plen + nlen;
+ size_t const big_stack = 1000;
+ wchar_t bigbuf[big_stack];
+ wchar_t *resbuf = amount <= big_stack ? bigbuf : (wchar_t *)malloc(sizeof(wchar_t) * amount);
+ if (!resbuf)
+ return nullptr;
+ /* ident = "_" + priv[ipriv:] + ident # i.e. 1+plen+nlen bytes */
+ resbuf[0] = '_';
+ if (PyUnicode_AsWideChar(privateobj, resbuf + 1, ipriv + plen) < 0)
+ return nullptr;
+ if (PyUnicode_AsWideChar(name, resbuf + ipriv + plen + 1, nlen) < 0)
+ return nullptr;
+ PyObject *result = PyUnicode_FromWideChar(resbuf + ipriv, 1 + plen + nlen);
+ if (amount > big_stack)
+ free(resbuf);
+ return result;
+}
+
+/*****************************************************************************
+ *
+ * Runtime support for Python 3.8 incompatibilities
+ *
+ */
+
+int PepRuntime_38_flag = 0;
+
+static void
+init_PepRuntime()
+{
+ // We expect a string of the form "\d\.\d+\."
+ const char *version = Py_GetVersion();
+ if (version[0] < '3')
+ return;
+ if (std::atoi(version + 2) >= 8)
+ PepRuntime_38_flag = 1;
+}
+
+static long _GetPepRuntimeVersion()
+{
+ auto *version = PySys_GetObject("version_info");
+ const auto major = PyLong_AsLong(PyTuple_GetItem(version, 0));
+ const auto minor = PyLong_AsLong(PyTuple_GetItem(version, 1));
+ const auto micro = PyLong_AsLong(PyTuple_GetItem(version, 2));
+ return major << 16 | minor << 8 | micro;
+}
+
+long _PepRuntimeVersion()
+{
+ static const auto number = _GetPepRuntimeVersion();
+ return number;
+}
+
+/*****************************************************************************
+ *
+ * PYSIDE-535: Support for PyPy
+ *
+ * This has the nice side effect of a more clean implementation,
+ * and we don't keep the old macro version.
+ *
+ */
+
+///////////////////////////////////////////////////////////////////////
+//
+// PEP 697: Support for embedded type structures.
+//
+// According to `https://docs.python.org/3/c-api/object.html?highlight=pyobject_gettypedata#c.PyObject_GetTypeData`
+// the function `PyObject_GetTypeData` should belong to the Stable API
+// since version 3.12.0, but it does not. We use instead some copies
+// from Python source code.
+
+#if !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+# define PepObject_GetTypeData PyObject_GetTypeData
+
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
+{
+ // PYSIDE-2676: Use the meta type explicitly.
+ // A derived type would fail the offset calculation.
+ static auto *meta = SbkObjectType_TypeF();
+ assert(SbkObjectType_Check(type));
+ auto *obType = reinterpret_cast<PyObject *>(type);
+ void *data = PyObject_GetTypeData(obType, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+}
+
+void PepType_SOTP_delete(PyTypeObject * /*type*/)
+{
+}
+
+#else
+
+// The following comments are directly copied from Python 3.12
+//
+
+// Make sure we have maximum alignment, even if the current compiler
+// does not support max_align_t. Note that:
+// - Autoconf reports alignment of unknown types to 0.
+// - 'long double' has maximum alignment on *most* platforms,
+// looks like the best we can do for pre-C11 compilers.
+// - The value is tested, see test_alignof_max_align_t
+# if !defined(ALIGNOF_MAX_ALIGN_T) || ALIGNOF_MAX_ALIGN_T == 0
+# undef ALIGNOF_MAX_ALIGN_T
+# define ALIGNOF_MAX_ALIGN_T alignof(long double)
+# endif
+
+/* Align up to the nearest multiple of alignof(max_align_t)
+ * (like _Py_ALIGN_UP, but for a size rather than pointer)
+ */
+static Py_ssize_t _align_up(Py_ssize_t size)
+{
+ return (size + ALIGNOF_MAX_ALIGN_T - 1) & ~(ALIGNOF_MAX_ALIGN_T - 1);
+}
+
+static void *PepObject_GetTypeData(PyObject *obj, PyTypeObject *cls)
+{
+ assert(PyObject_TypeCheck(obj, cls));
+ return reinterpret_cast<char *>(obj) + _align_up(cls->tp_base->tp_basicsize);
+}
+//
+///////////////////////////////////////////////////////////////////////
+
+/*
+ * PyTypeObject extender
+ */
+
+static std::unordered_map<PyTypeObject *, SbkObjectTypePrivate > SOTP_extender{};
+static thread_local PyTypeObject *SOTP_key{};
+static thread_local SbkObjectTypePrivate *SOTP_value{};
+
+SbkObjectTypePrivate *PepType_SOTP(PyTypeObject *type)
+{
+ static auto *meta = SbkObjectType_TypeF();
+ static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+ assert(SbkObjectType_Check(type));
+ if (use_312) {
+ auto *obType = reinterpret_cast<PyObject *>(type);
+ void *data = PepObject_GetTypeData(obType, meta);
+ return reinterpret_cast<SbkObjectTypePrivate *>(data);
+ }
+ if (type == SOTP_key)
+ return SOTP_value;
+ auto it = SOTP_extender.find(type);
+ if (it == SOTP_extender.end()) {
+ it = SOTP_extender.insert({type, {}}).first;
+ memset(&it->second, 0, sizeof(SbkObjectTypePrivate));
+ }
+ SOTP_key = type;
+ SOTP_value = &it->second;
+ return SOTP_value;
+}
+
+void PepType_SOTP_delete(PyTypeObject *type)
+{
+ static bool use_312 = _PepRuntimeVersion() >= 0x030C00;
+ assert(SbkObjectType_Check(type));
+ if (use_312)
+ return;
+ SOTP_extender.erase(type);
+ SOTP_key = nullptr;
+}
+
+#endif // !defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030C0000
+
+/*
+ * SbkEnumType extender
+ */
+static std::unordered_map<SbkEnumType *, SbkEnumTypePrivate> SETP_extender{};
+static thread_local SbkEnumType *SETP_key{};
+static thread_local SbkEnumTypePrivate *SETP_value{};
+
+SbkEnumTypePrivate *PepType_SETP(SbkEnumType *enumType)
+{
+ // PYSIDE-2230: This makes no sense at all for Enum types.
+ if (enumType == SETP_key)
+ return SETP_value;
+ auto it = SETP_extender.find(enumType);
+ if (it == SETP_extender.end()) {
+ it = SETP_extender.insert({enumType, {}}).first;
+ memset(&it->second, 0, sizeof(SbkEnumTypePrivate));
+ }
+ SETP_key = enumType;
+ SETP_value = &it->second;
+ return SETP_value;
+}
+
+void PepType_SETP_delete(SbkEnumType *enumType)
+{
+ SETP_extender.erase(enumType);
+ SETP_key = nullptr;
+}
+
+#ifdef Py_LIMITED_API
+static PyObject *emulatePyType_GetDict(PyTypeObject *type)
+{
+ if (_PepRuntimeVersion() < 0x030C00 || type->tp_dict) {
+ auto *res = type->tp_dict;
+ Py_XINCREF(res);
+ return res;
+ }
+ // PYSIDE-2230: Here we are really cheating. We don't know how to
+ // access an internal dict, and so we simply pretend
+ // it were an empty dict. This works great for our types.
+ // This was an unexpectedly simple solution :D
+ return PyDict_New();
+}
+#endif
+
+// PyType_GetDict: replacement for <static type>.tp_dict, which is
+// zero for builtin types since 3.12.
+PyObject *PepType_GetDict(PyTypeObject *type)
+{
+#if !defined(Py_LIMITED_API)
+# if PY_VERSION_HEX >= 0x030C0000
+ return PyType_GetDict(type);
+# else
+ // pre 3.12 fallback code, mimicking the addref-behavior.
+ Py_XINCREF(type->tp_dict);
+ return type->tp_dict;
+# endif
+#else
+ return emulatePyType_GetDict(type);
+#endif // Py_LIMITED_API
+}
+
+int PepType_SetDict(PyTypeObject *type, PyObject *dict)
+{
+ type->tp_dict = dict;
+ return 0;
+}
+
+// Pre 3.10, PyType_GetSlot() would only work for heap types.
+// FIXME: PyType_GetSlot() can be used unconditionally when the
+// minimum limited API version is >= 3.10.
+void *PepType_GetSlot(PyTypeObject *type, int aSlot)
+{
+ static const bool is310 = _PepRuntimeVersion() >= 0x030A00;
+ if (is310 || (type->tp_flags & Py_TPFLAGS_HEAPTYPE) != 0)
+ return PyType_GetSlot(type, aSlot);
+
+ switch (aSlot) {
+ case Py_tp_alloc:
+ return reinterpret_cast<void *>(type->tp_alloc);
+ case Py_tp_getattro:
+ return reinterpret_cast<void *>(type->tp_getattro);
+ case Py_tp_setattro:
+ return reinterpret_cast<void *>(type->tp_setattro);
+ case Py_tp_descr_get:
+ return reinterpret_cast<void *>(type->tp_descr_get);
+ case Py_tp_descr_set:
+ return reinterpret_cast<void *>(type->tp_descr_set);
+ case Py_tp_call:
+ return reinterpret_cast<void *>(type->tp_call);
+ case Py_tp_new:
+ return reinterpret_cast<void *>(type->tp_new);
+ case Py_tp_init:
+ return reinterpret_cast<void *>(type->tp_init);
+ case Py_tp_free:
+ return reinterpret_cast<void *>(type->tp_free);
+ }
+ assert(false);
+ return nullptr;
+}
+
+/***************************************************************************
+ *
+ * PYSIDE-535: The enum/flag error
+ * -------------------------------
+ *
+ * This is a fragment of the code which was used to find the enum/flag
+ * alias error. See the change to `setTypeConverter` in sbkenum.cpp .
+ *
+
+Usage:
+
+python3 -c "from PySide6 import QtCore" 2>&1 | python3 tools/debug_renamer.py | uniq -c | head -10
+
+ 5 PepType_ExTP:940 x_A SOTP s=96
+ 4 PepType_ExTP:940 x_B SETP s=24
+ 2 PepType_ExTP:940 x_C PFTP s=16
+ 4 PepType_ExTP:940 x_D SETP s=24
+ 1 PepType_ExTP:940 x_C SETP s=24
+ 2 PepType_ExTP:940 x_E PFTP s=16
+ 4 PepType_ExTP:940 x_F SETP s=24
+ 1 PepType_ExTP:940 x_E SETP s=24
+ 4 PepType_ExTP:940 x_G SETP s=24
+ 4 PepType_ExTP:940 x_H SETP s=24
+
+static inline void *PepType_ExTP(PyTypeObject *type, size_t size)
+{
+ static const char *env_p = std::getenv("PFTP");
+ if (env_p) {
+ static PyTypeObject *alias{};
+ const char *kind = size == sizeof(SbkObjectTypePrivate) ? "SOTP" :
+ size == sizeof(SbkEnumTypePrivate) ? "SETP" :
+ size == sizeof(SbkQFlagsTypePrivate) ? "PFTP" :
+ "unk.";
+ fprintf(stderr, "%s:%d %p x %s s=%ld\n", __func__, __LINE__, type, kind, size);
+ PyObject *kill{};
+ if (strlen(env_p) > 0) {
+ if (size == sizeof(SbkQFlagsTypePrivate)) {
+ if (alias == nullptr)
+ alias = type;
+ }
+ if (size != sizeof(SbkQFlagsTypePrivate)) {
+ if (type == alias)
+ Py_INCREF(kill);
+ }
+ }
+ }
+ const auto ikey = reinterpret_cast<std::uintptr_t>(type);
+ if (ikey == cached_key)
+ return cached_value;
+ auto it = SOTP_extender.find(ikey);
+ if (it == SOTP_extender.end()) {
+ PepType_ExTP_init(type, size);
+ return PepType_ExTP(type, size);
+ }
+ cached_key = ikey;
+ cached_value = reinterpret_cast<void *>(it->second);
+ return cached_value;
+}
+*/
+
+/*****************************************************************************
+ *
+ * Module Initialization
+ *
+ */
+
+void
+Pep384_Init()
+{
+ init_PepRuntime();
+#ifdef Py_LIMITED_API
+ check_PyTypeObject_valid();
+ Pep_GetVerboseFlag();
+ PepMethod_TypePtr = getMethodType();
+ PepFunction_TypePtr = getFunctionType();
+ PepStaticMethod_TypePtr = getStaticMethodType();
+#endif // Py_LIMITED_API
+#ifdef PYPY_VERSION
+ PepBuiltinMethod_TypePtr = getBuiltinMethodType();
+#endif
+}
+
+} // extern "C"