Author: Antonio Cuni <anto.c...@gmail.com> Branch: extradoc Changeset: r5896:02a6dcd8289f Date: 2018-09-04 01:57 +0200 http://bitbucket.org/pypy/extradoc/changeset/02a6dcd8289f/
Log: one more section diff --git a/blog/draft/2018-09-cpyext/cpyext.rst b/blog/draft/2018-09-cpyext/cpyext.rst --- a/blog/draft/2018-09-cpyext/cpyext.rst +++ b/blog/draft/2018-09-cpyext/cpyext.rst @@ -134,3 +134,51 @@ can potentially move and change their underlying memory address; on the other hand, we need a way to represent them as fixed-address ``PyObject *`` when we pass them to C extensions. We surely need a way to handle that. + + +`PyObject *` in PyPy +--------------------- + +Another challenge is that sometimes, ``PyObject *`` structs are not completely +opaque: there are parts of the public API which expose to the user specific +fields of some concrete C struct, for example the definition of PyTypeObject_: +since the low-level layout of PyPy ``W_Root`` objects is completely different +than the one used by CPython, we cannot simply pass RPython objects to C; we +need a way to handle the difference. + +.. _PyTypeObject: https://docs.python.org/2/c-api/typeobj.html + +So, we have two issues so far: objects which can move, and incompatible +low-level layouts. ``cpyext`` solves both by decoupling the RPython and the C +representations: we have two "views" of the same entity, depending on whether +we are in the PyPy world (the moving ``W_Root`` subclass) or in the C world +(the non-movable ``PyObject *``). + +``PyObject *`` are created lazily, only when they are actually needed: the +vast majority of PyPy objects are never passed to any C extension, so we don't +pay any penalty in that case; however, the first time we pass a ``W_Root`` to +C, we allocate and initialize its ``PyObject *`` counterpart. + +The same idea applies also to objects which are created in C, e.g. by calling +_`PyObject_New`: at first, only the ``PyObject *`` exists and it is +exclusively managed by reference counting: as soon as we pass it to the PyPy +world (e.g. as a return value of a function call), we create its ``W_Root`` +counterpart, which is managed by the GC as usual. + +.. _`PyObject_New`: https://docs.python.org/2/c-api/allocation.html#c.PyObject_New + +Here we start to see why calling cpyext modules is more costly in PyPy than in +CPython: we need to pay some penalty for all the conversions between +``W_Root`` and ``PyObject *``. + +Moreover, the first time we pass a ``W_Root`` to C we also need to allocate +the memory for the ``PyObject *`` using a slowish "CPython-style" memory +allocator: in practice, for all the objects which are passed to C we pay more +or less the same costs as CPython, thus effectively "undoing" the speedup +guaranteed by PyPy's Generational GC under normal circumstances. + + +Maintaining the link between ``W_Root`` and ``PyObject *`` +----------------------------------------------------------- + +WRITE ME _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit