Well, I discussed this issue hundreds of times with Victor Stinner.

I believe that this is what we have to go even if there is a very
little minor performance issue, it will be not a big hurdle.
we can see the benchmark from https://speed.python.org/ and CPython become
faster and faster.
Converting macros to functions will overcome the issue which has been
pointed out as known as implementation detail leak.

Regards,
Dong-hee

2021년 10월 20일 (수) 오전 9:59, Victor Stinner <vstin...@python.org>님이 작성:

> Hi,
>
> Erlend and me wrote a PEP to move away from macros in the Python C
> API. We are now waiting for feedback :-) Read the PEP online:
> https://www.python.org/dev/peps/pep-0670/
>
> There is a copy of the PEP below for inline replies.
>
> Victor
>
> ---
>
> PEP: 670
> Title: Convert macros to functions in the Python C API
> Author: Erlend Egeberg Aasland <erlend.aasl...@protonmail.com>,
>         Victor Stinner <vstin...@python.org>
> Status: Draft
> Type: Standards Track
> Content-Type: text/x-rst
> Created: 19-Oct-2021
> Python-Version: 3.11
>
>
> Abstract
> ========
>
> Convert macros to static inline functions or regular functions.
>
> Remove the return value of macros having a return value, whereas they
> should not, to aid detecting bugs in C extensions when the C API is
> misused.
>
> Some function arguments are still cast to ``PyObject*`` to prevent
> emitting new compiler warnings.
>
>
> Rationale
> =========
>
> The use of macros may have unintended adverse effects that are hard to
> avoid, even for experienced C developers. Some issues have been known
> for years, while others have been discovered recently in Python.
> Working around macro pitfalls makes the macro coder harder to read and
> to maintain.
>
> Converting macros to functions has multiple advantages:
>
> * By design, functions don't have macro pitfalls.
> * Arguments type and return type are well defined.
> * Debuggers and profilers can retrieve the name of inlined functions.
> * Debuggers can put breakpoints on inlined functions.
> * Variables have a well defined scope.
> * Code is usually easier to read and to maintain than similar macro
>   code.  Functions don't need the following workarounds for macro
>   pitfalls:
>
>   * Add parentheses around arguments.
>   * Use line continuation characters if the function is written on
>     multiple lines.
>   * Add commas to execute multiple expressions.
>   * Use ``do { ... } while (0)`` to write multiple statements.
>
> Converting macros and static inline functions to regular functions makes
> these regular functions accessible to projects which use Python but
> cannot use macros and static inline functions.
>
>
> Macro Pitfalls
> ==============
>
> The `GCC documentation
> <https://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html>`_ lists several
> common macro pitfalls:
>
> - Misnesting
> - Operator precedence problems
> - Swallowing the semicolon
> - Duplication of side effects
> - Self-referential macros
> - Argument prescan
> - Newlines in arguments
>
>
> Performance and inlining
> ========================
>
> Static inline functions is a feature added to the C99 standard. Modern C
> compilers have efficient heuristics to decide if a function should be
> inlined or not.
>
> When a C compiler decides to not inline, there is likely a good reason.
> For example, inlining would reuse a register which require to
> save/restore the register value on the stack and so increase the stack
> memory usage or be less efficient.
>
>
> Debug build
> -----------
>
> When Python is built in debug mode, most compiler optimizations are
> disabled.  For example, Visual Studio disables inlining. Benchmarks must
> not be run on a Python debug build, only on release build: using LTO and
> PGO is recommended for reliable benchmarks. PGO helps the compiler to
> decide if function should be inlined or not.
>
>
> Force inlining
> --------------
>
> The ``Py_ALWAYS_INLINE`` macro can be used to force inlining. This macro
> uses ``__attribute__((always_inline))`` with GCC and Clang, and
> ``__forceinline`` with MSC.
>
> So far, previous attempts to use ``Py_ALWAYS_INLINE`` didn't show any
> benefit and were abandoned. See for example: `bpo-45094
> <https://bugs.python.org/issue45094>`_: "Consider using
> ``__forceinline`` and ``__attribute__((always_inline))`` on static
> inline functions (``Py_INCREF``, ``Py_TYPE``) for debug build".
>
> When the ``Py_INCREF()`` macro was converted to a static inline
> functions in 2018 (`commit
> <
> https://github.com/python/cpython/commit/2aaf0c12041bcaadd7f2cc5a54450eefd7a6ff12
> >`__),
> it was decided not to force inlining. The machine code was analyzed with
> multiple C compilers and compiler options: ``Py_INCREF()`` was always
> inlined without having to force inlining. The only case where it was not
> inlined was the debug build. See discussion in the `bpo-35059
> <https://bugs.python.org/issue35059>`_: "Convert ``Py_INCREF()`` and
> ``PyObject_INIT()`` to inlined functions".
>
>
> Disable inlining
> ----------------
>
> 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
> especially useful on a LTO+PGO build which is more aggressive to inline
> code: see `bpo-33720 <https://bugs.python.org/issue33720>`_. The
> ``Py_NO_INLINE`` macro uses ``__attribute__ ((noinline))`` with GCC and
> Clang, and ``__declspec(noinline)`` with MSC.
>
>
> Specification
> =============
>
> Convert macros to static inline functions
> -----------------------------------------
>
> Most macros should be converted to static inline functions to prevent
> `macro pitfalls`_.
>
> The following macros should not be converted:
>
> * Empty macros. Example: ``#define Py_HAVE_CONDVAR``.
> * Macros only defining a number, even if a constant with a well defined
>   type can better. Example: ``#define METH_VARARGS 0x0001``.
> * Compatibility layer for different C compilers, C language extensions,
>   or recent C features.
>   Example: ``#define Py_ALWAYS_INLINE __attribute__((always_inline))``.
>
>
> Convert static inline functions to regular functions
> ----------------------------------------------------
>
> The performance impact of converting static inline functions to regular
> functions should be measured with benchmarks. If there is a significant
> slowdown, there should be a good reason to do the conversion. One reason
> can be hiding implementation details.
>
> Using static inline functions in the internal C API is fine: the
> internal C API exposes implemenation details by design and should not be
> used outside Python.
>
> Cast to PyObject*
> -----------------
>
> When a macro is converted to a function and the macro casts its
> arguments to ``PyObject*``, the new function comes with a new macro
> which cast arguments to ``PyObject*`` to prevent emitting new compiler
> warnings. So the converted functions still accept pointers to structures
> inheriting from ``PyObject`` (ex: ``PyTupleObject``).
>
> For example, the ``Py_TYPE(obj)`` macro casts its ``obj`` argument to
> ``PyObject*``::
>
>     #define _PyObject_CAST_CONST(op) ((const PyObject*)(op))
>
>     static inline PyTypeObject* _Py_TYPE(const PyObject *ob) {
>         return ob->ob_type;
>     }
>     #define Py_TYPE(ob) _Py_TYPE(_PyObject_CAST_CONST(ob))
>
> The undocumented private ``_Py_TYPE()`` function must not be called
> directly. Only the documented public ``Py_TYPE()`` macro must be used.
>
> Later, the cast can be removed on a case by case basis, but that is out
> of scope for this PEP.
>
> Remove the return value
> -----------------------
>
> 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
> misused in third party C extensions. See `bpo-30459
> <https://bugs.python.org/issue30459>`_ for the example of
> ``PyList_SET_ITEM()`` and ``PyCell_SET()`` macros. It is not easy to
> 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.
>
>
> Backwards Compatibility
> =======================
>
> Removing the return value of macros is an incompatible API change made
> on purpose: see the `Remove the return value`_ section.
>
>
> Rejected Ideas
> ==============
>
> Keep macros, but fix some macro issues
> --------------------------------------
>
> Converting macros to functions is not needed to `remove the return
> value`_: casting a macro return value to ``void`` also fix the issue.
> For example, the ``PyList_SET_ITEM()`` macro was already fixed like
> that.
>
> Macros are always "inlined" with any C compiler.
>
> The duplication of side effects can be worked around in the caller of
> the macro.
>
> People using macros should be considered "consenting adults". People who
> feel unsafe with macros should simply not use them.
>
> Examples of hard to read macros
> ===============================
>
> _Py_NewReference()
> ------------------
>
> Example showing the usage of an ``#ifdef`` inside a macro.
>
> Python 3.7 macro (simplified code)::
>
>     #ifdef COUNT_ALLOCS
>     #  define _Py_INC_TPALLOCS(OP) inc_count(Py_TYPE(OP))
>     #  define _Py_COUNT_ALLOCS_COMMA  ,
>     #else
>     #  define _Py_INC_TPALLOCS(OP)
>     #  define _Py_COUNT_ALLOCS_COMMA
>     #endif /* COUNT_ALLOCS */
>
>     #define _Py_NewReference(op) (                   \
>         _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA  \
>         Py_REFCNT(op) = 1)
>
> Python 3.8 function (simplified code)::
>
>     static inline void _Py_NewReference(PyObject *op)
>     {
>         _Py_INC_TPALLOCS(op);
>         Py_REFCNT(op) = 1;
>     }
>
> PyObject_INIT()
> ---------------
>
> Example showing the usage of commas in a macro.
>
> Python 3.7 macro::
>
>     #define PyObject_INIT(op, typeobj) \
>         ( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)),
> (op) )
>
> Python 3.8 function (simplified code)::
>
>     static inline PyObject*
>     _PyObject_INIT(PyObject *op, PyTypeObject *typeobj)
>     {
>         Py_TYPE(op) = typeobj;
>         _Py_NewReference(op);
>         return op;
>     }
>
>     #define PyObject_INIT(op, typeobj) \
>         _PyObject_INIT(_PyObject_CAST(op), (typeobj))
>
> The function doesn't need the line continuation character. It has an
> explicit ``"return op;"`` rather than a surprising ``", (op)"`` at the
> end of the macro.  It uses one short statement per line, rather than a
> single long line. Inside the function, the *op* argument has a well
> defined type: ``PyObject*``.
>
>
> References
> ==========
>
> * `bpo-45490 <https://bugs.python.org/issue45490>`_:
>   [meta][C API] Avoid C macro pitfalls and usage of static inline
>   functions (October 2021).
> * `What to do with unsafe macros
>   <https://discuss.python.org/t/what-to-do-with-unsafe-macros/7771>`_
>   (March 2021).
> * `bpo-43502 <https://bugs.python.org/issue43502>`_:
>   [C-API] Convert obvious unsafe macros to static inline functions
>   (March 2021).
>
>
> Copyright
> =========
>
> This document is placed in the public domain or under the
> CC0-1.0-Universal license, whichever is more permissive.
> --
> Night gathers, and now my watch begins. It shall not end until my death.
> _______________________________________________
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/2GN646CGWGTO6ZHHU7JTA5XWDF4ULM77/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Software Development Engineer at Line corp.

Tel: +82 10-3353-9127
Email: donghee.n...@gmail.com | donghee...@python.org |
donghee...@linecorp.com
Linkedin: https://www.linkedin.com/in/dong-hee-na-2b713b49/
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/JMT7TH37GMUKJNHVCZ7RXXPTPAXKQ2PG/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to