Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions pep-0590.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ It introduces a new "vectorcall" protocol and calling convention.
This is based on the "fastcall" convention, which is already used internally by CPython.
The new features can be used by any user-defined extension class.

Most of the new API is private in CPython 3.8.
The plan is to finalize semantics and make it public in Python 3.9.

**NOTE**: This PEP deals only with the Python/C API,
it does not affect the Python language or standard library.

Expand Down Expand Up @@ -43,6 +46,13 @@ This is inefficient for calls to classes as several intermediate objects need to
For a class ``cls``, at least one intermediate object is created for each call in the sequence
``type.__call__``, ``cls.__new__``, ``cls.__init__``.

This PEP proposes an interface for use by extension modules.
Such interfaces cannot effectively be tested, or designed, without having the
consumers in the loop.
For that reason, we provide private (underscore-prefixed) names.
The API may change (based on consumer feedback) in Python 3.9, where we expect
it to be finalized, and the underscores removed.


Specification
=============
Expand All @@ -64,12 +74,12 @@ Changes to the ``PyTypeObject`` struct
--------------------------------------

The unused slot ``printfunc tp_print`` is replaced with ``tp_vectorcall_offset``. It has the type ``Py_ssize_t``.
A new ``tp_flags`` flag is added, ``Py_TPFLAGS_HAVE_VECTORCALL``,
A new ``tp_flags`` flag is added, ``_Py_TPFLAGS_HAVE_VECTORCALL``,
which must be set for any class that uses the vectorcall protocol.

If ``Py_TPFLAGS_HAVE_VECTORCALL`` is set, then ``tp_vectorcall_offset`` must be a positive integer.
If ``_Py_TPFLAGS_HAVE_VECTORCALL`` is set, then ``tp_vectorcall_offset`` must be a positive integer.
It is the offset into the object of the vectorcall function pointer of type ``vectorcallfunc``.
This pointer may be ``NULL``, in which case the behavior is the same as if ``Py_TPFLAGS_HAVE_VECTORCALL`` was not set.
This pointer may be ``NULL``, in which case the behavior is the same as if ``_Py_TPFLAGS_HAVE_VECTORCALL`` was not set.

The ``tp_print`` slot is reused as the ``tp_vectorcall_offset`` slot to make it easier for for external projects to backport the vectorcall protocol to earlier Python versions.
In particular, the Cython project has shown interest in doing that (see https://mail.python.org/pipermail/python-dev/2018-June/153927.html).
Expand All @@ -79,7 +89,7 @@ Descriptor behavior

One additional type flag is specified: ``Py_TPFLAGS_METHOD_DESCRIPTOR``.

``Py_TPFLAGS_METHOD_DESCRIPTOR`` should be set if the the callable uses the descriptor protocol to create a bound method-like object.
``Py_TPFLAGS_METHOD_DESCRIPTOR`` should be set if the callable uses the descriptor protocol to create a bound method-like object.
This is used by the interpreter to avoid creating temporary objects when calling methods
(see ``_PyObject_GetMethod`` and the ``LOAD_METHOD``/``CALL_METHOD`` opcodes).

Expand Down Expand Up @@ -127,7 +137,7 @@ New C API and changes to CPython

The following functions or macros are added to the C API:

- ``PyObject *PyObject_Vectorcall(PyObject *obj, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords)``:
- ``PyObject *_PyObject_Vectorcall(PyObject *obj, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords)``:
Calls ``obj`` with the given arguments.
Note that ``nargs`` may include the flag ``PY_VECTORCALL_ARGUMENTS_OFFSET``.
The actual number of positional arguments is given by ``PyVectorcall_NARGS(nargs)``.
Expand All @@ -148,7 +158,7 @@ The following functions or macros are added to the C API:
Subclassing
-----------

Extension types inherit the type flag ``Py_TPFLAGS_HAVE_VECTORCALL``
Extension types inherit the type flag ``_Py_TPFLAGS_HAVE_VECTORCALL``
and the value ``tp_vectorcall_offset`` from the base class,
provided that they implement ``tp_call`` the same way as the base class.
Additionally, the flag ``Py_TPFLAGS_METHOD_DESCRIPTOR``
Expand All @@ -160,6 +170,23 @@ This restriction may be lifted in the future, but that would require
special-casing ``__call__`` in ``type.__setattribute__``.


Finalizing the API
==================

The underscore in the names ``_PyObject_Vectorcall`` and
``_Py_TPFLAGS_HAVE_VECTORCALL`` indicates that this API may change in minor
Python versions.
When finalized (which is planned for Python 3.9), they will be renamed to
``PyObject_Vectorcall`` and ``Py_TPFLAGS_HAVE_VECTORCALL``.
The old underscore-prefixed names will remain available as aliases.

The new API will be documented as normal, but will warn of the above.

Semantics for the other names introduced in this PEP (``PyVectorcall_NARGS``,
``PyVectorcall_Call``, ``Py_TPFLAGS_METHOD_DESCRIPTOR``,
``PY_VECTORCALL_ARGUMENTS_OFFSET``) are final.


Internal CPython changes
========================

Expand Down Expand Up @@ -202,7 +229,7 @@ Third-party extension classes using vectorcall

To enable call performance on a par with Python functions and built-in functions,
third-party callables should include a ``vectorcallfunc`` function pointer,
set ``tp_vectorcall_offset`` to the correct value and add the ``Py_TPFLAGS_HAVE_VECTORCALL`` flag.
set ``tp_vectorcall_offset`` to the correct value and add the ``_Py_TPFLAGS_HAVE_VECTORCALL`` flag.
Any class that does this must implement the ``tp_call`` function and make sure its behaviour is consistent with the ``vectorcallfunc`` function.
Setting ``tp_call`` to ``PyVectorcall_Call`` is sufficient.

Expand Down