PEP 670 amendments (#2157)

This commit is contained in:
Erlend Egeberg Aasland 2021-11-24 19:23:36 +01:00 committed by GitHub
parent 2263e93426
commit c1fda6822b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 61 additions and 27 deletions

View File

@ -60,13 +60,13 @@ The `GCC documentation
<https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html>`_ lists several <https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html>`_ lists several
common macro pitfalls: common macro pitfalls:
- Misnesting; - Misnesting
- Operator precedence problems; - Operator precedence problems
- Swallowing the semicolon; - Swallowing the semicolon
- Duplication of side effects; - Duplication of side effects
- Self-referential macros; - Self-referential macros
- Argument prescan; - Argument prescan
- Newlines in arguments. - Newlines in arguments
Performance and inlining Performance and inlining
@ -91,7 +91,7 @@ performances and reliable benchmarks. PGO helps the compiler to decide
if function should be inlined or not. if function should be inlined or not.
``./configure --with-pydebug`` uses the ``-Og`` compiler option if it's ``./configure --with-pydebug`` uses the ``-Og`` compiler option if it's
supported by the compiler (GCC and LLVM clang support it): optimize supported by the compiler (GCC and LLVM Clang support it): optimize
debugging experience. Otherwise, the ``-O0`` compiler option is used: debugging experience. Otherwise, the ``-O0`` compiler option is used:
disable most optimizations. disable most optimizations.
@ -119,11 +119,10 @@ The ``Py_ALWAYS_INLINE`` macro can be used to force inlining. This macro
uses ``__attribute__((always_inline))`` with GCC and Clang, and uses ``__attribute__((always_inline))`` with GCC and Clang, and
``__forceinline`` with MSC. ``__forceinline`` with MSC.
So far, previous attempts to use ``Py_ALWAYS_INLINE`` didn't show any Previous attempts to use ``Py_ALWAYS_INLINE`` didn't show any benefit, and were
benefit and were abandoned. See for example: `bpo-45094 abandoned. See for example: `bpo-45094 <https://bugs.python.org/issue45094>`_:
<https://bugs.python.org/issue45094>`_: "Consider using "Consider using ``__forceinline`` and ``__attribute__((always_inline))`` on
``__forceinline`` and ``__attribute__((always_inline))`` on static static inline functions (``Py_INCREF``, ``Py_TYPE``) for debug build".
inline functions (``Py_INCREF``, ``Py_TYPE``) for debug build".
When the ``Py_INCREF()`` macro was converted to a static inline When the ``Py_INCREF()`` macro was converted to a static inline
functions in 2018 (`commit functions in 2018 (`commit
@ -140,8 +139,8 @@ Disable inlining
---------------- ----------------
On the other side, the ``Py_NO_INLINE`` macro can be used to disable On the other side, the ``Py_NO_INLINE`` macro can be used to disable
inlining. It is useful to reduce the stack memory usage. It is inlining. It can be used to reduce the stack memory usage, or to prevent
especially useful on a LTO+PGO build which is more aggressive to inline inlining on LTO+PGO builds, which are generally more aggressive to inline
code: see `bpo-33720 <https://bugs.python.org/issue33720>`_. The code: see `bpo-33720 <https://bugs.python.org/issue33720>`_. The
``Py_NO_INLINE`` macro uses ``__attribute__ ((noinline))`` with GCC and ``Py_NO_INLINE`` macro uses ``__attribute__ ((noinline))`` with GCC and
Clang, and ``__declspec(noinline)`` with MSC. Clang, and ``__declspec(noinline)`` with MSC.
@ -164,6 +163,7 @@ The following macros should not be converted:
* Compatibility layer for different C compilers, C language extensions, * Compatibility layer for different C compilers, C language extensions,
or recent C features. or recent C features.
Example: ``#define Py_ALWAYS_INLINE __attribute__((always_inline))``. Example: ``#define Py_ALWAYS_INLINE __attribute__((always_inline))``.
* Macros that need the stringification or concatenation feature of the C preprocessor.
Convert static inline functions to regular functions Convert static inline functions to regular functions
@ -189,7 +189,7 @@ Cast to PyObject*
When a macro is converted to a function and the macro casts its When a macro is converted to a function and the macro casts its
arguments to ``PyObject*``, the new function comes with a new macro arguments to ``PyObject*``, the new function comes with a new macro
which cast arguments to ``PyObject*`` to prevent emitting new compiler which cast arguments to ``PyObject*`` to prevent emitting new compiler
warnings. So the converted functions still accept pointers to other warnings. This implies that a converted function will accept pointers to
structures inheriting from ``PyObject`` (ex: ``PyTupleObject``). structures inheriting from ``PyObject`` (ex: ``PyTupleObject``).
For example, the ``Py_TYPE(obj)`` macro casts its ``obj`` argument to For example, the ``Py_TYPE(obj)`` macro casts its ``obj`` argument to
@ -212,14 +212,10 @@ Remove the return value
----------------------- -----------------------
When a macro is implemented as an expression, it has an implicit return When a macro is implemented as an expression, it has an implicit return
value. In some cases, the macro must not have a return value and can be value. This macro pitfall can be misused in third party C extensions. See
misused in third party C extensions. See `bpo-30459 `bpo-30459 <https://bugs.python.org/issue30459>`_ regarding the misuse of the
<https://bugs.python.org/issue30459>`_ for the example of ``PyList_SET_ITEM()`` and ``PyCell_SET()`` macros. Such pitfalls are hard to
``PyList_SET_ITEM()`` and ``PyCell_SET()`` macros. It is not easy to catch while reviewing macro code. Removing the return value aids detecting
notice this issue while reviewing macro code.
These macros are converted to functions using the ``void`` return type
to remove their return value. Removing the return value aids detecting
bugs in C extensions when the C API is misused. bugs in C extensions when the C API is misused.
@ -249,9 +245,9 @@ the macro.
People using macros should be considered "consenting adults". People who People using macros should be considered "consenting adults". People who
feel unsafe with macros should simply not use them. feel unsafe with macros should simply not use them.
The idea was rejected because macros are error prone and it is too easy These ideas are rejected because macros _are_ error prone, and it is too easy
to miss a macro pitfall when writing a macro. Moreover, macros are to miss a macro pitfall when writing and reviewing macro code. Moreover, macros
harder to read and to maintain than functions. are harder to read and maintain than functions.
Examples of hard to read macros Examples of hard to read macros
@ -318,6 +314,44 @@ Python 3.8 function (simplified code)::
} }
PyUnicode_READ_CHAR()
---------------------
This macro reuses arguments, and possibly calls ``PyUnicode_KIND`` multiple
times::
#define PyUnicode_READ_CHAR(unicode, index) \
(assert(PyUnicode_Check(unicode)), \
assert(PyUnicode_IS_READY(unicode)), \
(Py_UCS4) \
(PyUnicode_KIND((unicode)) == PyUnicode_1BYTE_KIND ? \
((const Py_UCS1 *)(PyUnicode_DATA((unicode))))[(index)] : \
(PyUnicode_KIND((unicode)) == PyUnicode_2BYTE_KIND ? \
((const Py_UCS2 *)(PyUnicode_DATA((unicode))))[(index)] : \
((const Py_UCS4 *)(PyUnicode_DATA((unicode))))[(index)] \
) \
))
Possible implementation as a static inlined function::
static inline Py_UCS4
PyUnicode_READ_CHAR(PyObject *unicode, Py_ssize_t index)
{
assert(PyUnicode_Check(unicode));
assert(PyUnicode_IS_READY(unicode));
switch (PyUnicode_KIND(unicode)) {
case PyUnicode_1BYTE_KIND:
return (Py_UCS4)((const Py_UCS1 *)(PyUnicode_DATA(unicode)))[index];
case PyUnicode_2BYTE_KIND:
return (Py_UCS4)((const Py_UCS2 *)(PyUnicode_DATA(unicode)))[index];
case PyUnicode_4BYTE_KIND:
default:
return (Py_UCS4)((const Py_UCS4 *)(PyUnicode_DATA(unicode)))[index];
}
}
Macros converted to functions since Python 3.8 Macros converted to functions since Python 3.8
============================================== ==============================================