aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/libshiboken/pep384impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/libshiboken/pep384impl.cpp')
-rw-r--r--sources/shiboken2/libshiboken/pep384impl.cpp294
1 files changed, 3 insertions, 291 deletions
diff --git a/sources/shiboken2/libshiboken/pep384impl.cpp b/sources/shiboken2/libshiboken/pep384impl.cpp
index 39fdc37ad..25a3b625b 100644
--- a/sources/shiboken2/libshiboken/pep384impl.cpp
+++ b/sources/shiboken2/libshiboken/pep384impl.cpp
@@ -43,297 +43,9 @@
extern "C"
{
-/**********************************************************************
- **********************************************************************
-
-
- The New Type API
- ================
-
- After converting everything but the "object.h" file, we could not
- believe our eyes: it suddenly was clear that we would have no more
- access to type objects, and even more scary that all types which we
- use have to be heap types, only!
-
- For PySide with it's intense use of heap type extensions in various
- flavors, it seemed to be quite unsolvable. In the end, it was
- nicely solved, but it took almost 3.5 months to get that right.
-
- Before we see how this is done, we will explain the differences
- between the APIs and their consequences.
-
-
- The Interface
- -------------
-
- The old type API of Python knows static types and heap types.
- Static types are written down as a declaration of a PyTypeObject
- structure with all its fields filled in. Here is for example
- the definition of the Python type "object":
-
- PyTypeObject PyBaseObject_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "object", |* tp_name *|
- sizeof(PyObject), |* tp_basicsize *|
- 0, |* tp_itemsize *|
- object_dealloc, |* tp_dealloc *|
- 0, |* tp_print *|
- 0, |* tp_getattr *|
- 0, |* tp_setattr *|
- 0, |* tp_reserved *|
- object_repr, |* tp_repr *|
- 0, |* tp_as_number *|
- 0, |* tp_as_sequence *|
- 0, |* tp_as_mapping *|
- (hashfunc)_Py_HashPointer, |* tp_hash *|
- 0, |* tp_call *|
- object_str, |* tp_str *|
- PyObject_GenericGetAttr, |* tp_getattro *|
- PyObject_GenericSetAttr, |* tp_setattro *|
- 0, |* tp_as_buffer *|
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, |* tp_flags *|
- PyDoc_STR("object()\n--\n\nThe most base type"), |* tp_doc *|
- 0, |* tp_traverse *|
- 0, |* tp_clear *|
- object_richcompare, |* tp_richcompare *|
- 0, |* tp_weaklistoffset *|
- 0, |* tp_iter *|
- 0, |* tp_iternext *|
- object_methods, |* tp_methods *|
- 0, |* tp_members *|
- object_getsets, |* tp_getset *|
- 0, |* tp_base *|
- 0, |* tp_dict *|
- 0, |* tp_descr_get *|
- 0, |* tp_descr_set *|
- 0, |* tp_dictoffset *|
- object_init, |* tp_init *|
- PyType_GenericAlloc, |* tp_alloc *|
- object_new, |* tp_new *|
- PyObject_Del, |* tp_free *|
- };
-
- We can write the same structure in form of a PyType_Spec structure,
- and there is even a tool that does this for us, but I had to fix a
- few things because there is little support for this.
-
- The tool is XXX go home and continue.....
-
-
-
-
- The Transition To Simpler Types
- ===============================
-
- After all code has been converted to the limited API, there is the
- PyHeapTypeObject remaining as a problem.
-
- Why a problem? Well, all the type structures in shiboken use
- special extra fields at the end of the heap type object. This
- currently enforces knowledge at compile time about how large the
- heap type object is. In a clean implementation, we would only use
- the PyTypeObject itself and access the fields "behind" the type
- by a pointer that is computed at runtime.
-
-
- Excursion: PepTypeObject
- ------------------------
-
- Before we are going into details, let us motivate the existence of
- the PepTypeObject, an alias to PyTypeObject:
-
- Originally, we wanted to use PyTypeObject as an opaque type and
- restrict ourselves to only use the access function PyType_GetSlot.
- This function allows access to all fields which are supported by
- the limited API.
-
- But this is a restriction, because we get no access to tp_dict,
- which we need to support the signature extension. But we can work
- around that.
-
- The real restriction is that PyType_GetSlot only works for heap
- types. This makes the function quite useless, because we have
- no access to PyType_Type, which is the most important type "type"
- in Python. We need that for instance to compute the size of
- PyHeapTypeObject dynamically.
-
- With much effort, it is possible to clone PyType_Type as a heap
- type. But due to a bug in the Pep 384 support, we need
- access to the nb_index field of a normal type. Cloning does not
- help because PyNumberMethods fields are not inherited.
-
- After I realized this dead end, I changed the concept and did not
- use PyType_GetSlot at all (except in function copyNumberMethods),
- but created PepTypeObject as a remake of PyTypeObject with only
- those fields defined that are needed in PySide.
-
- Is this breakage of the limited API? I don't think so. A special
- function runs on program startup that checks the correct position
- of the fields of PepHeapType, although a change in those fields is
- more than unlikely.
- The really crucial thing is to no longer use PyHeapTypeObject
- explicitly because that _does_ change its layout over time.
-
-
- Diversification
- ---------------
-
- There are multiple SbkXXX structures which all use a "d" field
- for their private data. This makes it not easy to find the right
- fields when switching between types and objects.
-
- struct LIBSHIBOKEN_API SbkObjectType
- {
- PyHeapTypeObject super;
- SbkObjectTypePrivate *d;
- };
-
- struct LIBSHIBOKEN_API SbkObject
- {
- PyObject_HEAD
- PyObject *ob_dict;
- PyObject *weakreflist;
- SbkObjectPrivate *d;
- };
-
- The first step was to rename the SbkObjectTypePrivate from "d" to
- "sotp". It was chosen to be short but easy to remember.
-
-
- Abstraction
- -----------
-
- After renaming the type extension pointers to "sotp", I replaced
- them by function-like macros which did the special access "behind"
- the types, instead of those explicit fields. For instance, the
- expression
-
- type->sotp->converter
-
- became
-
- PepType_SOTP(type)->converter
-
- The macro expression can be seen here:
-
- #define _genericTypeExtender(etype) \
- (reinterpret_cast<char*>(etype) + \
- (reinterpret_cast<PepTypeObject *>(&PyType_Type))->tp_basicsize)
-
- #define PepType_SOTP(etype) \
- (*reinterpret_cast<SbkObjectTypePrivate**>(_genericTypeExtender(etype)))
-
- It looks complicated, but in the end there is only a single new
- indirection via PyType_Type, which happens at runtime. This is the
- key to fulfil what Pep 384 wants: No version-dependent fields.
-
-
- Simplification
- --------------
-
- After all type extension fields were replaced by macro calls, we
- could remove the version dependent definition
-
- typedef struct _pepheaptypeobject {
- union {
- PepTypeObject ht_type;
- void *opaque[PY_HEAPTYPE_SIZE];
- };
- } PepHeapTypeObject;
-
- and the version dependent structure
-
- struct LIBSHIBOKEN_API SbkObjectType
- {
- PepHeapTypeObject super;
- SbkObjectTypePrivate *sotp;
- };
-
- could be replaced by the simplified
-
- struct LIBSHIBOKEN_API SbkObjectType
- {
- PepTypeObject type;
- };
-
- which is no longer version-dependent.
-
-
- Verification Of PepTypeObject
- =============================
-
- We have introduced PepTypeObject as a new alias for PyTypeObject,
- and now we need to prove that we are allowed to do so.
-
- When using the limited API as intended, then types are completely
- opaque, and access is only through PyType_FromSpec and (from
- version 3.5 upwards) through PyType_GetSlot.
-
- Python then uses all the slot definitions in the type description
- and produces a regular type object.
-
-
- Unused Information
- ------------------
-
- But we know many things about types that are not explicitly said,
- but they are inherently clear:
-
- a) The basic structure of a type is always the same, regardless
- if it is a static type or a heap type.
-
- b) types are evolving very slowly, and a field is never replaced
- by another field with different semantics.
-
- Inherent rule a) gives us the following information: If we calculate
- the offsets of the fields, then this info is also usable for non-
- -heap types.
-
- The validation checks if rule b) is still valid.
-
-
- How it Works
- ------------
-
- The basic idea of the validation is to produce a new type using
- PyType_FromSpec and to see where in the type structure these fields
- show up. So we build a PyType_Slot structure with all the fields we
- are using and make sure that these values are all unique in the
- type.
-
- Most fields are not investigated by PyType_FromSpec, and so we
- simply used some numeric value. Some fields are interpreted, like
- tp_members. This field must really be a PyMemberDef. And there are
- tp_base and tp_bases which have to be type objects and lists
- thereof. It was easiest to not produce these fields from scratch
- but use them from the "type" object PyType_Type.
-
- Then one would think to write a function that searches the known
- values in the opaque type structure.
-
- But we can do better and use optimistically the observation (b):
- We simply use the PepTypeObject structure and assume that every
- field lands exactly where we are awaiting it.
-
- And that is the whole proof: If we find all the disjoint values at
- the places where we expect them, thenthis is q.e.d. :)
-
-
- About tp_dict
- -------------
-
- One word about the tp_dict field: This field is a bit special in
- the proof, since it does not appear in the spec and cannot easily
- be checked by "type.__dict__" because that creates a dictproxy
- object. So how do we proove that is really the right dict?
-
- We have to create that PyMethodDef structure anyway, and instead of
- leaving it empty, we insert a dummy function. Then we ask the
- tp_dict field if it has that object in it, and that's q.e.d.
-
-
- *********/
-
+/*
+ * The documentation is located in pep384impl_doc.rst
+ */
/*****************************************************************************
*