Clarify PEP 523 with the settled C API for co_extra (#97)

This commit is contained in:
Brett Cannon 2016-09-07 11:45:16 -07:00 committed by GitHub
parent 5426603a2b
commit 81572832aa
1 changed files with 24 additions and 28 deletions

View File

@ -84,39 +84,35 @@ One field is to be added to the ``PyCodeObject`` struct
typedef struct {
...
PyObject *co_extra; /* "Scratch space" for the code object. */
_PyCodeObjectExtra co_extra; /* "Scratch space" for the code object. */
} PyCodeObject;
The ``co_extra`` will be ``NULL`` by default and will not be used by
CPython itself. Third-party code is free to use the field as desired.
Values stored in the field are expected to not be required in order
for the code object to function, allowing the loss of the data of the
field to be acceptable. The field will be freed like all other fields
on ``PyCodeObject`` during deallocation using ``Py_XDECREF()``.
The ``co_extra`` will be ``NULL`` by default and it is not planned to
be used by CPython itself. Third-party code is free to use the field
as desired. Values stored in the field are expected to not be required
in order for the code object to function, allowing the loss of the
data of the field to be acceptable.
Code using the field is expected to always store a tuple in the field.
This allows for multiple users of the field to not trample over each
other while being as performant as possible. Typical usage of the
field is expected to roughly follow the following pseudo-code::
A private API has been introduced to work with the field::
if co_extra is None:
data = DataClass()
co_extra = (data,)
else:
assert isinstance(co_extra, tuple)
for x in co_extra:
if isinstance(x, DataClass):
data = x
break
else:
data = DataClass()
co_extra += (data,)
PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index,
void **extra);
PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
void *extra);
Using a list was considered but was found to be less performant, and
with a key use-case being JIT usage the performance consideration it
was deemed more important to use a tuple than a list. A tuple also
makes more sense semantically as the objects stored in the tuple will
be heterogeneous.
Users of the field are expected to call
``_PyEval_RequestCodeExtraIndex()`` to receive (what should be
considered) an opaque index value to adding data into ``co-extra``.
With that index, users can set data using ``_PyCode_SetExtra()`` and
later retrieve the data with ``_PyCode_GetExtra()``. The API is
purposefully listed as private to communicate the fact that there are
no semantic guarantees of the API between Python releases.
Using a list and tuple were considered but was found to be less
performant, and with a key use-case being JIT usage the performance
consideration won out for using a custom struct instead of a Python
object.
A dict was also considered, but once again performance was more
important. While a dict will have constant overhead in looking up