PEP 590: minor edits (#973)
This commit is contained in:
parent
ad9c99dd8d
commit
92f4dbdbf1
44
pep-0590.rst
44
pep-0590.rst
|
@ -59,10 +59,10 @@ Changes to the ``PyTypeObject``
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
The a new slot called ``tp_vectorcall_offset`` is added. It has the type ``uint32_t``.
|
The a new slot called ``tp_vectorcall_offset`` is added. It has the type ``uint32_t``.
|
||||||
A new flag is added, ``Py_TPFLAGS_HAVE_VECTOR_CALL``, which is set for any new PyTypeObjects that include the
|
A new flag is added, ``Py_TPFLAGS_HAVE_VECTORCALL``, which is set for any new PyTypeObjects that include the
|
||||||
``tp_vectorcall_offset`` member.
|
``tp_vectorcall_offset`` member.
|
||||||
|
|
||||||
If ``Py_TPFLAGS_HAS_VECTORCALL`` is set then ``tp_vectorcall_offset`` is the offset
|
If ``Py_TPFLAGS_HAVE_VECTORCALL`` is set then ``tp_vectorcall_offset`` is the offset
|
||||||
into the object of the ``vectorcall`` function-pointer.
|
into the object of the ``vectorcall`` function-pointer.
|
||||||
|
|
||||||
The unused slot ``printfunc tp_print`` is replaced with ``vectorcall tp_vectorcall``, so that classes
|
The unused slot ``printfunc tp_print`` is replaced with ``vectorcall tp_vectorcall``, so that classes
|
||||||
|
@ -71,21 +71,21 @@ can support the vectorcall calling convention.
|
||||||
Additional flags
|
Additional flags
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
One additional flag is specified: ``PY_METHOD_DESCRIPTOR``.
|
One additional flag is specified: ``Py_TPFLAGS_METHOD_DESCRIPTOR``.
|
||||||
|
|
||||||
``PY_METHOD_DESCRIPTOR`` should be set if the the callable uses the descriptor protocol to create a method or method-like object.
|
``Py_TPFLAGS_METHOD_DESCRIPTOR`` should be set if the the callable uses the descriptor protocol to create a method or method-like object.
|
||||||
This is used by the interpreter to avoid creating temporary objects when calling methods.
|
This is used by the interpreter to avoid creating temporary objects when calling methods.
|
||||||
|
|
||||||
If this flag is set for a class ``F``, then instances of that class are expected to behave the same as a Python function when used as a class attribute.
|
If this flag is set for a class ``F``, then instances of that class are expected to behave the same as a Python function when used as a class attribute.
|
||||||
Specifically, this mean that the value of ``c.m`` where ``C.m`` is an instanceof the class ``F`` (and ``c`` is an instance of ``C``)
|
Specifically, this means that the value of ``c.m`` where ``C.m`` is an instance of the class ``F`` (and ``c`` is an instance of ``C``)
|
||||||
must be an object that acts like a bound-method binding ``C.m`` and ``c``.
|
must be an object that acts like a bound method binding ``C.m`` and ``c``.
|
||||||
This flag is necessary if custom callables are to be able to behave like Python functions *and* be called as efficiently as Python or built-in functions.
|
This flag is necessary if custom callables are to be able to behave like Python functions *and* be called as efficiently as Python or built-in functions.
|
||||||
|
|
||||||
The call
|
The call
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The call takes the form ``((vectorcall)(((char *)o)+offset))(o, n, args, kwnames)`` where
|
The call takes the form ``((vectorcall)(((char *)o)+offset))(o, n, args, kwnames)`` where
|
||||||
``offset`` is ``TYPE(o)->tp_vectorcall``
|
``offset`` is ``Py_TYPE(o)->tp_vectorcall_offset``.
|
||||||
The caller is responsible for creating the ``kwnames`` tuple and ensuring that there are no duplicates in it.
|
The caller is responsible for creating the ``kwnames`` tuple and ensuring that there are no duplicates in it.
|
||||||
``n`` is the number of postional arguments plus ``PY_VECTORCALL_ARGUMENTS_OFFSET`` if the argument vector pointer points to argument 1 in the
|
``n`` is the number of postional arguments plus ``PY_VECTORCALL_ARGUMENTS_OFFSET`` if the argument vector pointer points to argument 1 in the
|
||||||
allocated vector.
|
allocated vector.
|
||||||
|
@ -94,7 +94,7 @@ allocated vector.
|
||||||
Example of how ``PY_VECTORCALL_ARGUMENTS_OFFSET`` is used by a callee to avoid allocation [3]_
|
Example of how ``PY_VECTORCALL_ARGUMENTS_OFFSET`` is used by a callee to avoid allocation [3]_
|
||||||
|
|
||||||
Whenever they can do so cheaply (without allocation) callers are encouraged to offset the arguments.
|
Whenever they can do so cheaply (without allocation) callers are encouraged to offset the arguments.
|
||||||
Doing so will allow callables such as bound-methods to make their onward calls cheaply.
|
Doing so will allow callables such as bound methods to make their onward calls cheaply.
|
||||||
The interpreter already allocates space on the stack for the callable, so it can offset its arguments for no additional cost.
|
The interpreter already allocates space on the stack for the callable, so it can offset its arguments for no additional cost.
|
||||||
|
|
||||||
Continued prohibition of callable classes as base classes
|
Continued prohibition of callable classes as base classes
|
||||||
|
@ -107,7 +107,7 @@ If callables could be sub-classed then any call to a ``function`` or a ``method_
|
||||||
New C API and changes to CPython
|
New C API and changes to CPython
|
||||||
================================
|
================================
|
||||||
|
|
||||||
``PyObject *PyObject_VectorCallWithCallable(PyObject *func, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``
|
``PyObject *PyObject_VectorCallWithCallable(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``
|
||||||
Calls ``obj`` with the given arguments.
|
Calls ``obj`` with the given arguments.
|
||||||
Note that ``nargs`` is the number of positional arguments; no offsetting is allowed.
|
Note that ``nargs`` is the number of positional arguments; no offsetting is allowed.
|
||||||
|
|
||||||
|
@ -118,16 +118,16 @@ Note that ``nargs`` is the number of positional arguments, including the callabl
|
||||||
Both functions raise an exception if ``obj`` is not callable.
|
Both functions raise an exception if ``obj`` is not callable.
|
||||||
|
|
||||||
Two utility functions are provided to call the new calling convention from the old one, or vice-versa.
|
Two utility functions are provided to call the new calling convention from the old one, or vice-versa.
|
||||||
These functions are ``PyObject *``PyCall_MakeVectorCall(PyObject *obj, PyObject *tuple, PyObject **dict);`` and
|
These functions are ``PyObject *PyCall_MakeVectorCall(PyObject *obj, PyObject *tuple, PyObject **dict)`` and
|
||||||
``PyObject *PyCall_MakeTpCall(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames);``, respectively.
|
``PyObject *PyCall_MakeTpCall(PyObject *obj, PyObject **args, Py_ssize_t nargs, PyTupleObject *kwnames)``, respectively.
|
||||||
|
|
||||||
Both functions raise an exception if ``obj`` does not support the relevant protocol.
|
Both functions raise an exception if ``obj`` does not support the relevant protocol.
|
||||||
|
|
||||||
``METH_FASTCALL`` and ``METH_VECTORCALL`` flags
|
``METH_FASTCALL`` and ``METH_VECTORCALL`` flags
|
||||||
-----------------------------------------------
|
-----------------------------------------------
|
||||||
|
|
||||||
A new ``METH_VECTORCALL`` flag is added for specifying ``MethodDef`` structs. It is equivalent to the currently undocumented ``METH_FASTCALL | METH_KEYWORD`` flag.
|
A new ``METH_VECTORCALL`` flag is added for specifying ``PyMethodDef`` structs. It is equivalent to the currently undocumented ``METH_FASTCALL | METH_KEYWORD`` flags.
|
||||||
The new flag specifies that the function has the type ``PyObject *(*call) (PyObject * self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwname)``
|
The new flag specifies that the function has the type ``PyObject *(*call) (PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwname)``
|
||||||
|
|
||||||
Internal CPython changes
|
Internal CPython changes
|
||||||
========================
|
========================
|
||||||
|
@ -155,12 +155,12 @@ Third-party built-in classes using the new extended call interface
|
||||||
------------------------------------------------------------------
|
------------------------------------------------------------------
|
||||||
|
|
||||||
To enable call performance on a par with Python functions and built-in functions, third-party callables should include a ``vectorcall`` function pointer
|
To enable call performance on a par with Python functions and built-in functions, third-party callables should include a ``vectorcall`` function pointer
|
||||||
and set ``tp_vectorcall`` to the correct value.
|
and set ``tp_vectorcall_offset`` to the correct value.
|
||||||
Any class the sets ``tp_vectorcall`` to non-zero should also implement the ``tp_call`` function and make sure its behaviour is consistent with the ``vectorcall`` function.
|
Any class that sets ``tp_vectorcall_offset`` to non-zero should also implement the ``tp_call`` function and make sure its behaviour is consistent with the ``vectorcall`` function.
|
||||||
Setting ``tp_call`` to ``PyCall_MakeVectorCall`` will suffice.
|
Setting ``tp_call`` to ``PyCall_MakeVectorCall`` will suffice.
|
||||||
|
|
||||||
The `MethodDef` protocol and Argument Clinic
|
The ``PyMethodDef`` protocol and Argument Clinic
|
||||||
============================================
|
================================================
|
||||||
|
|
||||||
Argument Clinic [4]_ automatically generates wrapper functions around lower-level callables, providing safe unboxing of primitive types and
|
Argument Clinic [4]_ automatically generates wrapper functions around lower-level callables, providing safe unboxing of primitive types and
|
||||||
other safety checks.
|
other safety checks.
|
||||||
|
@ -190,20 +190,18 @@ This PEP is broader in scope than PEP 576 and uses variable rather than fixed of
|
||||||
The underlying calling convention is similar. Because PEP 576 only allows a fixed offset for the function pointer,
|
The underlying calling convention is similar. Because PEP 576 only allows a fixed offset for the function pointer,
|
||||||
it would not allow the improvements to any objects with constraints on their layout.
|
it would not allow the improvements to any objects with constraints on their layout.
|
||||||
|
|
||||||
PEP 580 proposes a major change to the `MethodDef` protocol used to define builtin functions.
|
PEP 580 proposes a major change to the ``PyMethodDef`` protocol used to define builtin functions.
|
||||||
This PEP provides a more general and simpler mechanism in the form of a new calling convention.
|
This PEP provides a more general and simpler mechanism in the form of a new calling convention.
|
||||||
This PEP also extends the `MethodDef` protocol, but merely to formalise existing conventions.
|
This PEP also extends the ``PyMethodDef`` protocol, but merely to formalise existing conventions.
|
||||||
PEP 580 is specifically targetted at function-like objects, and doesn't support other callables like classes, partial functions,
|
|
||||||
or proxies.
|
|
||||||
|
|
||||||
Other rejected approaches
|
Other rejected approaches
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
A longer, 6 argument, form combining both the vector and optional tuple and dictionary arguments was considered.
|
A longer, 6 argument, form combining both the vector and optional tuple and dictionary arguments was considered.
|
||||||
However, it was found that the code to convert between it and the old `tp_call` form was overly cumbersome and inefficient.
|
However, it was found that the code to convert between it and the old ``tp_call`` form was overly cumbersome and inefficient.
|
||||||
Also, since only 4 arguments are passed in registers on x64 Windows, the two extra arguments would have non-neglible costs.
|
Also, since only 4 arguments are passed in registers on x64 Windows, the two extra arguments would have non-neglible costs.
|
||||||
|
|
||||||
Removing any special cases and making all calls use the `tp_call` form was also considered.
|
Removing any special cases and making all calls use the ``tp_call`` form was also considered.
|
||||||
However, unless a much more efficient way was found to create and destroy tuples, and to a lesser extent dictionaries,
|
However, unless a much more efficient way was found to create and destroy tuples, and to a lesser extent dictionaries,
|
||||||
then it would be too slow.
|
then it would be too slow.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue