aboutsummaryrefslogtreecommitdiffstats
path: root/sources
diff options
context:
space:
mode:
authorChristian Tismer <tismer@stackless.com>2022-11-30 12:41:34 +0100
committerChristian Tismer <tismer@stackless.com>2022-11-30 18:10:43 +0100
commitb7a809650fc4f911b2eda2ab3b8acfcc632ba61a (patch)
tree47ea0f0cd8dfc6def9d3c74ff17b805b6e885bac /sources
parenta997326ff9beef12bb0f99d057cd5a48a7f4549b (diff)
__feature__: Simplify and make more PyPy compatible
The fast_id_array does not make sense anymore and can be be replaced by integers. This not only simplifies debugging, but also makes it easier to support switching with PyPy, since PyPy does not guarantee unique numbers < 256. Feature selection can be almost completely offloaded from shiboken. This simplifies even more and can be beneficial when inlining. [ChangeLog][PySide6] The __feature__ switch has been simplified in preparation for eventual PyPy support. Task-number: PYSIDE-2029 Change-Id: I6060b5d81bfcde4fb4a9460e57e290f5690fe11d Pick-to: 6.4 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'sources')
-rw-r--r--sources/pyside6/libpyside/feature_select.cpp132
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.cpp45
-rw-r--r--sources/shiboken6/libshiboken/sbkfeature_base.h2
3 files changed, 75 insertions, 104 deletions
diff --git a/sources/pyside6/libpyside/feature_select.cpp b/sources/pyside6/libpyside/feature_select.cpp
index db28583c6..c12869777 100644
--- a/sources/pyside6/libpyside/feature_select.cpp
+++ b/sources/pyside6/libpyside/feature_select.cpp
@@ -97,10 +97,6 @@ typedef bool(*FeatureProc)(PyTypeObject *type, PyObject *prev_dict, int id);
static FeatureProc *featurePointer = nullptr;
-static PyObject *_fast_id_array[1 + 256] = {};
-// this will point to element 1 to allow indexing from -1
-static PyObject **fast_id_array;
-
// Create a derived dict class
static PyTypeObject *
createDerivedDictType()
@@ -142,15 +138,21 @@ static inline void setNextDict(PyObject *dict, PyObject *next_dict)
PyObject_SetAttr(dict, PyName::dict_ring(), next_dict);
}
-static inline void setSelectId(PyObject *dict, PyObject *select_id)
+static inline void setSelectId(PyObject *dict, int select_id)
{
- PyObject_SetAttr(dict, PyName::select_id(), select_id);
+ PyObject_SetAttr(dict, PyName::select_id(), PyLong_FromLong(select_id));
}
-static inline PyObject *getSelectId(PyObject *dict)
+static inline int getSelectId(PyObject *dict)
{
- auto select_id = PyObject_GetAttr(dict, PyName::select_id());
- return select_id;
+ auto *py_select_id = PyObject_GetAttr(dict, PyName::select_id());
+ if (py_select_id == nullptr) {
+ PyErr_Clear();
+ return 0;
+ }
+ int ret = PyLong_AsLong(py_select_id);
+ Py_DECREF(py_select_id);
+ return ret;
}
static bool replaceClassDict(PyTypeObject *type)
@@ -160,14 +162,13 @@ static bool replaceClassDict(PyTypeObject *type)
* This is mandatory for all type dicts when they are touched.
*/
ensureNewDictType();
- PyObject *dict = type->tp_dict;
- auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
- PyObject *new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ auto *dict = type->tp_dict;
+ auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr || PyDict_Update(new_dict, dict) < 0)
return false;
// Insert the default id. Cannot fail for small numbers.
- AutoDecRef select_id(PyLong_FromLong(0));
- setSelectId(new_dict, select_id);
+ setSelectId(new_dict, 0);
// insert the dict into itself as ring
setNextDict(new_dict, new_dict);
// We have now an exact copy of the dict with a new type.
@@ -177,15 +178,15 @@ static bool replaceClassDict(PyTypeObject *type)
return true;
}
-static bool addNewDict(PyTypeObject *type, PyObject *select_id)
+static bool addNewDict(PyTypeObject *type, int select_id)
{
/*
* Add a new dict to the ring and set it as `type->tp_dict`.
* A 'false' return is fatal.
*/
- auto dict = type->tp_dict;
- auto ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
- auto new_dict = PyObject_CallObject(ob_ndt, nullptr);
+ auto *dict = type->tp_dict;
+ auto *ob_ndt = reinterpret_cast<PyObject *>(new_dict_type);
+ auto *new_dict = PyObject_CallObject(ob_ndt, nullptr);
if (new_dict == nullptr)
return false;
setSelectId(new_dict, select_id);
@@ -197,16 +198,16 @@ static bool addNewDict(PyTypeObject *type, PyObject *select_id)
return true;
}
-static inline bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
+static inline bool moveToFeatureSet(PyTypeObject *type, int select_id)
{
/*
* Rotate the ring to the given `select_id` and return `true`.
* If not found, stay at the current position and return `false`.
*/
- auto initial_dict = type->tp_dict;
- auto dict = initial_dict;
+ auto *initial_dict = type->tp_dict;
+ auto *dict = initial_dict;
do {
- AutoDecRef current_id(getSelectId(dict));
+ int current_id = getSelectId(dict);
// This works because small numbers are singleton objects.
if (current_id == select_id) {
type->tp_dict = dict;
@@ -218,7 +219,7 @@ static inline bool moveToFeatureSet(PyTypeObject *type, PyObject *select_id)
return false;
}
-static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
+static bool createNewFeatureSet(PyTypeObject *type, int select_id)
{
/*
* Create a new feature set.
@@ -228,15 +229,8 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
* content in `prev_dict`. It is responsible of filling `type->tp_dict`
* with modified content.
*/
- static auto small_1 = PyLong_FromLong(255);
- Q_UNUSED(small_1);
- static auto small_2 = PyLong_FromLong(255);
- Q_UNUSED(small_2);
- // make sure that small integers are cached
- assert(small_1 != nullptr && small_1 == small_2);
-
- static auto zero = fast_id_array[0];
- bool ok = moveToFeatureSet(type, zero);
+
+ bool ok = moveToFeatureSet(type, 0);
Q_UNUSED(ok);
assert(ok);
@@ -244,7 +238,7 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
Py_INCREF(prev_dict); // keep the first ref unchanged
if (!addNewDict(type, select_id))
return false;
- auto id = PyLong_AsSsize_t(select_id);
+ int id = select_id;
if (id == -1)
return false;
FeatureProc *proc = featurePointer;
@@ -266,7 +260,7 @@ static bool createNewFeatureSet(PyTypeObject *type, PyObject *select_id)
return true;
}
-static inline void SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_id)
+static inline void SelectFeatureSetSubtype(PyTypeObject *type, int select_id)
{
/*
* This is the selector for one sublass. We need to call this for
@@ -288,6 +282,34 @@ static inline void SelectFeatureSetSubtype(PyTypeObject *type, PyObject *select_
}
}
+static PyObject *cached_globals{};
+static int last_select_id{};
+
+static inline int getFeatureSelectId()
+{
+ static auto *undef = PyLong_FromLong(-1);
+ static auto *feature_dict = GetFeatureDict();
+ // these things are all borrowed
+ auto *globals = PyEval_GetGlobals();
+ if (globals == nullptr
+ || globals == cached_globals)
+ return last_select_id;
+
+ auto *modname = PyDict_GetItem(globals, PyMagicName::name());
+ if (modname == nullptr)
+ return last_select_id;
+
+ auto *py_select_id = PyDict_GetItem(feature_dict, modname);
+ if (py_select_id == nullptr
+ || !PyLong_Check(py_select_id)
+ || py_select_id == undef)
+ return last_select_id;
+
+ cached_globals = globals;
+ last_select_id = PyLong_AsLong(py_select_id) & 0xff;
+ return last_select_id;
+}
+
static inline void SelectFeatureSet(PyTypeObject *type)
{
/*
@@ -306,8 +328,8 @@ static inline void SelectFeatureSet(PyTypeObject *type)
}
}
- PyObject *select_id = getFeatureSelectId(); // borrowed
- static PyObject *last_select_id{};
+ int select_id = getFeatureSelectId();
+ static int last_select_id{};
static PyTypeObject *last_type{};
// PYSIDE-2029: Implement a very simple but effective cache that cannot fail.
@@ -316,12 +338,11 @@ static inline void SelectFeatureSet(PyTypeObject *type)
last_type = type;
last_select_id = select_id;
- PyObject *mro = type->tp_mro;
+ auto *mro = type->tp_mro;
Py_ssize_t idx, n = PyTuple_GET_SIZE(mro);
// We leave 'Shiboken.Object' and 'object' alone, therefore "n - 2".
for (idx = 0; idx < n - 2; idx++) {
auto *sub_type = reinterpret_cast<PyTypeObject *>(PyTuple_GET_ITEM(mro, idx));
- // When any subtype is already resolved (false), we can stop.
SelectFeatureSetSubtype(sub_type, select_id);
}
// PYSIDE-1436: Clear all caches for the type and subtypes.
@@ -333,7 +354,7 @@ void Select(PyObject *obj)
{
if (featurePointer == nullptr)
return;
- auto type = Py_TYPE(obj);
+ auto *type = Py_TYPE(obj);
SelectFeatureSet(type);
}
@@ -364,12 +385,6 @@ static FeatureProc featureProcArray[] = {
nullptr
};
-void finalize()
-{
- for (int idx = -1; idx < 256; ++idx)
- Py_DECREF(fast_id_array[idx]);
-}
-
static bool patch_property_impl();
static bool is_initialized = false;
@@ -377,17 +392,14 @@ void init()
{
// This function can be called multiple times.
if (!is_initialized) {
- fast_id_array = &_fast_id_array[1];
- for (int idx = -1; idx < 256; ++idx)
- fast_id_array[idx] = PyLong_FromLong(idx);
featurePointer = featureProcArray;
initSelectableFeature(SelectFeatureSet);
- registerCleanupFunction(finalize);
patch_property_impl();
is_initialized = true;
}
+ last_select_id = 0;
// Reset the cache. This is called at any "from __feature__ import".
- initFeatureShibokenPart();
+ cached_globals = nullptr;
}
void Enable(bool enable)
@@ -417,7 +429,7 @@ static PyObject *methodWithNewName(PyTypeObject *type,
/*
* Create a method with a lower case name.
*/
- auto obtype = reinterpret_cast<PyObject *>(type);
+ auto *obtype = reinterpret_cast<PyObject *>(type);
int len = strlen(new_name);
auto name = new char[len + 1];
strcpy(name, new_name);
@@ -501,8 +513,8 @@ static PyObject *modifyStaticToClassMethod(PyTypeObject *type, PyObject *sm)
AutoDecRef func_ob(PyObject_GetAttr(sm, PyMagicName::func()));
if (func_ob.isNull())
return nullptr;
- auto func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
- auto new_func = new PyMethodDef;
+ auto *func = reinterpret_cast<PyCFunctionObject *>(func_ob.object());
+ auto *new_func = new PyMethodDef;
new_func->ml_name = func->m_ml->ml_name;
new_func->ml_meth = func->m_ml->ml_meth;
new_func->ml_flags = (func->m_ml->ml_flags & ~METH_STATIC) | METH_CLASS;
@@ -516,14 +528,14 @@ static PyObject *createProperty(PyTypeObject *type, PyObject *getter, PyObject *
assert(getter != nullptr);
if (setter == nullptr)
setter = Py_None;
- auto ptype = &PyProperty_Type;
+ auto *ptype = &PyProperty_Type;
if (Py_TYPE(getter) == PepStaticMethod_TypePtr) {
ptype = PyClassProperty_TypeF();
getter = modifyStaticToClassMethod(type, getter);
if (setter != Py_None)
setter = modifyStaticToClassMethod(type, setter);
}
- auto obtype = reinterpret_cast<PyObject *>(ptype);
+ auto *obtype = reinterpret_cast<PyObject *>(ptype);
PyObject *prop = PyObject_CallFunctionObjArgs(obtype, getter, setter, nullptr);
return prop;
}
@@ -692,7 +704,7 @@ static bool feature_02_true_property(PyTypeObject *type, PyObject *prev_dict, in
static PyObject *property_doc_get(PyObject *self, void *)
{
- auto po = reinterpret_cast<propertyobject *>(self);
+ auto *po = reinterpret_cast<propertyobject *>(self);
if (po->prop_doc != nullptr && po->prop_doc != Py_None) {
Py_INCREF(po->prop_doc);
@@ -700,7 +712,7 @@ static PyObject *property_doc_get(PyObject *self, void *)
}
if (po->prop_get) {
// PYSIDE-1019: Fetch the default `__doc__` from fget. We do it late.
- auto txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc());
+ auto *txt = PyObject_GetAttr(po->prop_get, PyMagicName::doc());
if (txt != nullptr) {
Py_INCREF(txt);
po->prop_doc = txt;
@@ -714,7 +726,7 @@ static PyObject *property_doc_get(PyObject *self, void *)
static int property_doc_set(PyObject *self, PyObject *value, void *)
{
- auto po = reinterpret_cast<propertyobject *>(self);
+ auto *po = reinterpret_cast<propertyobject *>(self);
Py_INCREF(value);
po->prop_doc = value;
@@ -731,8 +743,8 @@ static bool patch_property_impl()
{
// Turn `__doc__` into a computed attribute without changing writability.
auto gsp = property_getset;
- auto type = &PyProperty_Type;
- auto dict = type->tp_dict;
+ auto *type = &PyProperty_Type;
+ auto *dict = type->tp_dict;
AutoDecRef descr(PyDescr_NewGetSet(type, gsp));
if (descr.isNull())
return false;
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.cpp b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
index 9e28d1239..2931a8abd 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.cpp
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.cpp
@@ -19,41 +19,8 @@ extern "C"
////////////////////////////////////////////////////////////////////////////
//
-// getFeatureSelectId
+// Minimal __feature__ support in Shiboken
//
-// This function is needed here already for signature handling.
-// Maybe the same function from feature_select.cpp will be replaced.
-//
-
-static PyObject *cached_globals{};
-static PyObject *last_select_id{};
-
-PyObject *getFeatureSelectId()
-{
- static PyObject *undef = PyLong_FromLong(-1);
- static PyObject *feature_dict = GetFeatureDict();
- // these things are all borrowed
- PyObject *globals = PyEval_GetGlobals();
- if (globals == nullptr
- || globals == cached_globals)
- return last_select_id;
-
- PyObject *modname = PyDict_GetItem(globals, PyMagicName::name());
- if (modname == nullptr)
- return last_select_id;
-
- PyObject *select_id = PyDict_GetItem(feature_dict, modname);
- if (select_id == nullptr
- || !PyLong_Check(select_id)
- || select_id == undef)
- return last_select_id;
-
- cached_globals = globals;
- last_select_id = select_id;
- assert(PyLong_AsSsize_t(select_id) >= 0);
- return select_id;
-}
-
int currentSelectId(PyTypeObject *type)
{
PyObject *PyId = PyObject_GetAttr(type->tp_dict, PyName::select_id());
@@ -66,14 +33,6 @@ int currentSelectId(PyTypeObject *type)
return sel;
}
-void initFeatureShibokenPart()
-{
- static PyObject *no_sel = PyLong_FromLong(0);
- last_select_id = no_sel;
- // Reset the cache. This is called at any "from __feature__ import".
- cached_globals = nullptr;
-}
-
static SelectableFeatureHook SelectFeatureSet = nullptr;
SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
@@ -82,6 +41,8 @@ SelectableFeatureHook initSelectableFeature(SelectableFeatureHook func)
SelectFeatureSet = func;
return ret;
}
+//
+////////////////////////////////////////////////////////////////////////////
// This useful function is for debugging
void disassembleFrame(const char *marker)
diff --git a/sources/shiboken6/libshiboken/sbkfeature_base.h b/sources/shiboken6/libshiboken/sbkfeature_base.h
index 8d55297d7..290884062 100644
--- a/sources/shiboken6/libshiboken/sbkfeature_base.h
+++ b/sources/shiboken6/libshiboken/sbkfeature_base.h
@@ -7,9 +7,7 @@
extern "C"
{
-LIBSHIBOKEN_API PyObject *getFeatureSelectId();
LIBSHIBOKEN_API int currentSelectId(PyTypeObject *type);
-LIBSHIBOKEN_API void initFeatureShibokenPart();
LIBSHIBOKEN_API PyObject *mangled_type_getattro(PyTypeObject *type, PyObject *name);
LIBSHIBOKEN_API PyObject *Sbk_TypeGet___dict__(PyTypeObject *type, void *context);
LIBSHIBOKEN_API PyObject *SbkObject_GenericGetAttr(PyObject *obj, PyObject *name);