From 9ae598990246e709af06102f163c218429265e6c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 4 Feb 2026 15:11:38 +0100 Subject: [PATCH 01/13] Add "steal" term to glossary; clarify stealing on error With one exception, all "stealing" functions also steal on error, but it makes sense to note this in each case. --- Doc/c-api/bytes.rst | 9 +++++---- Doc/c-api/dict.rst | 4 ++-- Doc/c-api/exceptions.rst | 15 +++++++++------ Doc/c-api/gen.rst | 13 +++++++------ Doc/c-api/init.rst | 7 ++++--- Doc/c-api/intro.rst | 9 ++++++--- Doc/c-api/list.rst | 8 +++++--- Doc/c-api/module.rst | 8 ++++---- Doc/c-api/sequence.rst | 2 +- Doc/c-api/tuple.rst | 9 +++++---- Doc/c-api/unicode.rst | 3 ++- Doc/glossary.rst | 6 ++++++ 12 files changed, 56 insertions(+), 37 deletions(-) diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 82c2557368371f..5ecec86f16265a 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -180,10 +180,11 @@ called with a non-bytes parameter. .. c:function:: void PyBytes_Concat(PyObject **bytes, PyObject *newpart) Create a new bytes object in *\*bytes* containing the contents of *newpart* - appended to *bytes*; the caller will own the new reference. The reference to - the old value of *bytes* will be stolen. If the new object cannot be - created, the old reference to *bytes* will still be discarded and the value - of *\*bytes* will be set to ``NULL``; the appropriate exception will be set. + appended to *bytes*; the caller will own the new reference. + The reference to the old value of *bytes* will be ":term:`stolen `". + If the new object cannot be created, the old reference to *bytes* will still + be "stolen", the value of *\*bytes* will be set to ``NULL``, and + the appropriate exception will be set. .. c:function:: void PyBytes_ConcatAndDel(PyObject **bytes, PyObject *newpart) diff --git a/Doc/c-api/dict.rst b/Doc/c-api/dict.rst index 9c4428ced41b5a..a7302aff5fc4bd 100644 --- a/Doc/c-api/dict.rst +++ b/Doc/c-api/dict.rst @@ -84,8 +84,8 @@ Dictionary Objects Insert *val* into the dictionary *p* with a key of *key*. *key* must be :term:`hashable`; if it isn't, :exc:`TypeError` will be raised. Return - ``0`` on success or ``-1`` on failure. This function *does not* steal a - reference to *val*. + ``0`` on success or ``-1`` on failure. + This function *does not* ":term:`steal`" a reference to *val*. .. c:function:: int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val) diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst index 59af470f59ff34..13a04a08415881 100644 --- a/Doc/c-api/exceptions.rst +++ b/Doc/c-api/exceptions.rst @@ -503,7 +503,8 @@ Querying the error indicator .. warning:: - This call steals a reference to *exc*, which must be a valid exception. + This call ":term:`steals `" a reference to *exc*, + which must be a valid exception. .. versionadded:: 3.12 @@ -641,7 +642,8 @@ Querying the error indicator Set the exception info, as known from ``sys.exc_info()``. This refers to an exception that was *already caught*, not to an exception that was - freshly raised. This function steals the references of the arguments. + freshly raised. This function ":term:`steals `" the references + of the arguments. To clear the exception state, pass ``NULL`` for all three arguments. This function is kept for backwards compatibility. Prefer using :c:func:`PyErr_SetHandledException`. @@ -658,8 +660,8 @@ Querying the error indicator .. versionchanged:: 3.11 The ``type`` and ``traceback`` arguments are no longer used and can be NULL. The interpreter now derives them from the exception - instance (the ``value`` argument). The function still steals - references of all three arguments. + instance (the ``value`` argument). The function still + ":term:`steals `" references of all three arguments. Signal Handling @@ -844,7 +846,7 @@ Exception Objects Set the context associated with the exception to *ctx*. Use ``NULL`` to clear it. There is no type check to make sure that *ctx* is an exception instance. - This steals a reference to *ctx*. + This ":term:`steals `" a reference to *ctx*. .. c:function:: PyObject* PyException_GetCause(PyObject *ex) @@ -859,7 +861,8 @@ Exception Objects Set the cause associated with the exception to *cause*. Use ``NULL`` to clear it. There is no type check to make sure that *cause* is either an exception - instance or ``None``. This steals a reference to *cause*. + instance or ``None``. + This ":term:`steals `" a reference to *cause*. The :attr:`~BaseException.__suppress_context__` attribute is implicitly set to ``True`` by this function. diff --git a/Doc/c-api/gen.rst b/Doc/c-api/gen.rst index 74db49a6814800..3d51e7dacc3384 100644 --- a/Doc/c-api/gen.rst +++ b/Doc/c-api/gen.rst @@ -35,15 +35,15 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`. .. c:function:: PyObject* PyGen_New(PyFrameObject *frame) Create and return a new generator object based on the *frame* object. - A reference to *frame* is stolen by this function. The argument must not be - ``NULL``. + A reference to *frame* is ":term:`stolen `" by this function (even + on error). The argument must not be ``NULL``. .. c:function:: PyObject* PyGen_NewWithQualName(PyFrameObject *frame, PyObject *name, PyObject *qualname) Create and return a new generator object based on the *frame* object, with ``__name__`` and ``__qualname__`` set to *name* and *qualname*. - A reference to *frame* is stolen by this function. The *frame* argument - must not be ``NULL``. + A reference to *frame* is ":term:`stolen `" by this function (even + on error). The *frame* argument must not be ``NULL``. .. c:function:: PyCodeObject* PyGen_GetCode(PyGenObject *gen) @@ -68,8 +68,9 @@ Asynchronous Generator Objects .. c:function:: PyObject *PyAsyncGen_New(PyFrameObject *frame, PyObject *name, PyObject *qualname) Create a new asynchronous generator wrapping *frame*, with ``__name__`` and - ``__qualname__`` set to *name* and *qualname*. *frame* is stolen by this - function and must not be ``NULL``. + ``__qualname__`` set to *name* and *qualname*. + *frame* is ":term:`stolen `" by this function (even on error) and + must not be ``NULL``. On success, this function returns a :term:`strong reference` to the new asynchronous generator. On failure, this function returns ``NULL`` diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 7411644f9e110b..e05985146291a2 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -1481,9 +1481,10 @@ All of the following functions must be called after :c:func:`Py_Initialize`. .. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc) Asynchronously raise an exception in a thread. The *id* argument is the thread - id of the target thread; *exc* is the exception object to be raised. This - function does not steal any references to *exc*. To prevent naive misuse, you - must write your own C extension to call this. Must be called with an :term:`attached thread state`. + id of the target thread; *exc* is the exception object to be raised. + This function does not :term:`steal` any references to *exc*. + To prevent naive misuse, you must write your own C extension to call this. + Must be called with an :term:`attached thread state`. Returns the number of thread states modified; this is normally one, but will be zero if the thread id isn't found. If *exc* is ``NULL``, the pending exception (if any) for the thread is cleared. This raises no exceptions. diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 6886cd85b09a7d..71ddaf0766c210 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -532,9 +532,12 @@ the caller is said to *borrow* the reference. Nothing needs to be done for a Conversely, when a calling function passes in a reference to an object, there are two possibilities: the function *steals* a reference to the object, or it -does not. *Stealing a reference* means that when you pass a reference to a -function, that function assumes that it now owns that reference, and you are not -responsible for it any longer. +does not. + +*Stealing a reference* means that when you pass a reference to a +function, that function assumes that it now owns that reference. +Since the new owner can use :c:func:`!Py_DECREF` at its discretion, +you (the caller) must not use that reference after the call. .. index:: single: PyList_SetItem (C function) diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 758415a76e5cb4..7838a302d4888e 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -88,8 +88,10 @@ List Objects .. note:: - This function "steals" a reference to *item* and discards a reference to - an item already in the list at the affected position. + This function ":term:`steals `" a reference to *item*, + even on error. + On success, it discards a reference to an item already in the list + at the affected position (unless it was NULL). .. c:function:: void PyList_SET_ITEM(PyObject *list, Py_ssize_t i, PyObject *o) @@ -103,7 +105,7 @@ List Objects .. note:: - This macro "steals" a reference to *item*, and, unlike + This macro ":term:`steals `" a reference to *item*, and, unlike :c:func:`PyList_SetItem`, does *not* discard a reference to any item that is being replaced; any reference in *list* at position *i* will be leaked. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index e8a6e09f5554ec..8793e7dcdfad0b 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -900,8 +900,8 @@ or code that creates modules dynamically. .. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value) - Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference - to *value*. + Similar to :c:func:`PyModule_AddObjectRef`, but ":term:`steals `" + a reference to *value* (even on error). It can be called with a result of function that returns a new reference without bothering to check its result or even saving it to a variable. @@ -916,8 +916,8 @@ or code that creates modules dynamically. .. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value) - Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to - *value* on success (if it returns ``0``). + Similar to :c:func:`PyModule_AddObjectRef`, but :term:`steals ` + a reference to *value* on success (if it returns ``0``). The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef` functions are recommended, since it is diff --git a/Doc/c-api/sequence.rst b/Doc/c-api/sequence.rst index df5bf6b64a93a0..947a67145856e6 100644 --- a/Doc/c-api/sequence.rst +++ b/Doc/c-api/sequence.rst @@ -67,7 +67,7 @@ Sequence Protocol Assign object *v* to the *i*\ th element of *o*. Raise an exception and return ``-1`` on failure; return ``0`` on success. This is the equivalent of the Python statement ``o[i] = v``. This function *does - not* steal a reference to *v*. + not* ":term:`steal`" a reference to *v*. If *v* is ``NULL``, the element is deleted, but this feature is deprecated in favour of using :c:func:`PySequence_DelItem`. diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst index 3e3752696c46d8..6e84a4da3c2ec9 100644 --- a/Doc/c-api/tuple.rst +++ b/Doc/c-api/tuple.rst @@ -103,8 +103,9 @@ Tuple Objects .. note:: - This function "steals" a reference to *o* and discards a reference to - an item already in the tuple at the affected position. + This function ":term:`steals `" a reference to *o* and discards + a reference to an item already in the tuple at the affected position + (unless it was NULL). .. c:function:: void PyTuple_SET_ITEM(PyObject *p, Py_ssize_t pos, PyObject *o) @@ -117,7 +118,7 @@ Tuple Objects .. note:: - This function "steals" a reference to *o*, and, unlike + This function ":term:`steals `" a reference to *o*, and, unlike :c:func:`PyTuple_SetItem`, does *not* discard a reference to any item that is being replaced; any reference in the tuple at position *pos* will be leaked. @@ -260,7 +261,7 @@ type. .. note:: - This function "steals" a reference to *o*. + This function ":term:`steals `" a reference to *o*. .. c:function:: void PyStructSequence_SET_ITEM(PyObject *p, Py_ssize_t *pos, PyObject *o) diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst index d2b6643c700e88..47cd2626e3f0d5 100644 --- a/Doc/c-api/unicode.rst +++ b/Doc/c-api/unicode.rst @@ -679,7 +679,8 @@ APIs: Append the string *right* to the end of *p_left*. *p_left* must point to a :term:`strong reference` to a Unicode object; - :c:func:`!PyUnicode_Append` releases ("steals") this reference. + :c:func:`!PyUnicode_Append` releases (":term:`steals `") + this reference. On error, set *\*p_left* to ``NULL`` and set an exception. diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 7c41f5bc27b070..85d8252c022bbb 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1464,6 +1464,12 @@ Glossary stdlib An abbreviation of :term:`standard library`. + steal + In Python's C API, "*stealing*" an argument means that ownership of the + argument is transferred to the called function. + Generally, functions that "steal" an argument do so even if they fail. + See also :ref:`api-refcountdetails`. + strong reference In Python's C API, a strong reference is a reference to an object which is owned by the code holding the reference. The strong From 960b427d6ec2c945a2a67f6efadfabbb0d076120 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 5 Feb 2026 14:25:29 +0100 Subject: [PATCH 02/13] Update Doc/c-api/list.rst Co-authored-by: Peter Bierma --- Doc/c-api/list.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/c-api/list.rst b/Doc/c-api/list.rst index 7838a302d4888e..1d1c6e8658de38 100644 --- a/Doc/c-api/list.rst +++ b/Doc/c-api/list.rst @@ -91,7 +91,7 @@ List Objects This function ":term:`steals `" a reference to *item*, even on error. On success, it discards a reference to an item already in the list - at the affected position (unless it was NULL). + at the affected position (unless it was ``NULL``). .. c:function:: void PyList_SET_ITEM(PyObject *list, Py_ssize_t i, PyObject *o) From 3fd84bad6954f4a9544b705bb07a8899854d3e5f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Feb 2026 16:06:35 +0100 Subject: [PATCH 03/13] gh-140824: Fix _Py_DumpExtensionModules() to ignore sub-modules (#144339) Ignore "math.integer" extension if "math" is in sys.stdlib_module_names. --- Lib/test/test_faulthandler.py | 17 +++++++++++-- ...-01-30-13-23-06.gh-issue-140824.J1OCrC.rst | 2 ++ Python/pylifecycle.c | 24 +++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 874f52af857b94..5e88ae47775dbd 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -388,10 +388,11 @@ def test_disable(self): @skip_segfault_on_android def test_dump_ext_modules(self): + # Don't filter stdlib module names: disable sys.stdlib_module_names code = """ import faulthandler import sys - # Don't filter stdlib module names + import math sys.stdlib_module_names = frozenset() faulthandler.enable() faulthandler._sigsegv() @@ -403,9 +404,21 @@ def test_dump_ext_modules(self): if not match: self.fail(f"Cannot find 'Extension modules:' in {stderr!r}") modules = set(match.group(1).strip().split(', ')) - for name in ('sys', 'faulthandler'): + for name in ('sys', 'faulthandler', 'math'): self.assertIn(name, modules) + # Ignore "math.integer" sub-module if "math" package is + # in sys.stdlib_module_names + code = """ + import faulthandler + import math.integer + faulthandler.enable() + faulthandler._sigsegv() + """ + stderr, exitcode = self.get_output(code) + stderr = '\n'.join(stderr) + self.assertNotIn('Extension modules:', stderr) + def test_is_enabled(self): orig_stderr = sys.stderr try: diff --git a/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst b/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst new file mode 100644 index 00000000000000..dd90b6a21d135d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst @@ -0,0 +1,2 @@ +When :mod:`faulthandler` dumps the list of third-party extension modules, +ignore sub-modules of stdlib packages. Patch by Victor Stinner. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d3ed08de1d15d3..bb51f8d191c1c3 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3393,11 +3393,25 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) Py_hash_t hash; // if stdlib_module_names is not NULL, it is always a frozenset. while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { - if (PyUnicode_Check(item) - && PyUnicode_Compare(key, item) == 0) - { - is_stdlib_ext = 1; - break; + if (!PyUnicode_Check(item)) { + continue; + } + Py_ssize_t len = PyUnicode_GET_LENGTH(item); + if (PyUnicode_Tailmatch(key, item, 0, len, -1) == 1) { + Py_ssize_t key_len = PyUnicode_GET_LENGTH(key); + if (key_len == len) { + is_stdlib_ext = 1; + break; + } + assert(key_len > len); + + // Ignore sub-modules of stdlib packages. For example, + // ignore "math.integer" if key starts with "math.". + Py_UCS4 ch = PyUnicode_ReadChar(key, len); + if (ch == '.') { + is_stdlib_ext = 1; + break; + } } } if (is_stdlib_ext) { From 0b91f57a273dbd27a2987975ac203663a74cff3e Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 4 Feb 2026 17:08:23 +0100 Subject: [PATCH 04/13] gh-141984: Reword and reorganize Subscription (and Slicing) docs (GH-141985) Co-authored-by: Blaise Pabon Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/glossary.rst | 33 ++++- Doc/library/functions.rst | 20 +-- Doc/reference/datamodel.rst | 88 +++++++---- Doc/reference/expressions.rst | 257 +++++++++++++++++++++------------ Doc/reference/simple_stmts.rst | 41 +++--- 5 files changed, 283 insertions(+), 156 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 85d8252c022bbb..1afdc2db154360 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -786,6 +786,19 @@ Glossary An object that both finds and loads a module; both a :term:`finder` and :term:`loader` object. + index + A numeric value that represents the position of an element in + a :term:`sequence`. + + In Python, indexing starts at zero. + For example, ``things[0]`` names the *first* element of ``things``; + ``things[1]`` names the second one. + + In some contexts, Python allows negative indexes for counting from the + end of a sequence, and indexing using :term:`slices `. + + See also :term:`subscript`. + interactive Python has an interactive interpreter which means you can enter statements and expressions at the interpreter prompt, immediately @@ -863,6 +876,9 @@ Glossary CPython does not guarantee :term:`thread-safe` behavior of iterator operations. + key + A value that identifies an entry in a :term:`mapping`. + See also :term:`subscript`. key function A key function or collation function is a callable that returns a value @@ -1417,10 +1433,11 @@ Glossary chosen based on the type of a single argument. slice - An object usually containing a portion of a :term:`sequence`. A slice is - created using the subscript notation, ``[]`` with colons between numbers - when several are given, such as in ``variable_name[1:3:5]``. The bracket - (subscript) notation uses :class:`slice` objects internally. + An object of type :class:`slice`, used to describe a portion of + a :term:`sequence`. + A slice object is created when using the :ref:`slicing ` form + of :ref:`subscript notation `, with colons inside square + brackets, such as in ``variable_name[1:3:5]``. soft deprecated A soft deprecated API should not be used in new code, @@ -1484,6 +1501,14 @@ Glossary See also :term:`borrowed reference`. + subscript + The expression in square brackets of a + :ref:`subscription expression `, for example, + the ``3`` in ``items[3]``. + Usually used to select an element of a container. + Also called a :term:`key` when subscripting a :term:`mapping`, + or an :term:`index` when subscripting a :term:`sequence`. + synchronization primitive A basic building block for coordinating (synchronizing) the execution of multiple threads to ensure :term:`thread-safe` access to shared resources. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index cd819b8d06480a..65b8ffdb23111d 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1824,19 +1824,19 @@ are always available. They are listed here in alphabetical order. ``range(start, stop, step)``. The *start* and *step* arguments default to ``None``. - Slice objects have read-only data attributes :attr:`!start`, - :attr:`!stop`, and :attr:`!step` which merely return the argument - values (or their default). They have no other explicit functionality; - however, they are used by NumPy and other third-party packages. + Slice objects are also generated when :ref:`slicing syntax ` + is used. For example: ``a[start:stop:step]`` or ``a[start:stop, i]``. + + See :func:`itertools.islice` for an alternate version that returns an + :term:`iterator`. .. attribute:: slice.start - .. attribute:: slice.stop - .. attribute:: slice.step + slice.stop + slice.step - Slice objects are also generated when extended indexing syntax is used. For - example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See - :func:`itertools.islice` for an alternate version that returns an - :term:`iterator`. + These read-only attributes are set to the argument values + (or their default). They have no other explicit functionality; + however, they are used by NumPy and other third-party packages. .. versionchanged:: 3.12 Slice objects are now :term:`hashable` (provided :attr:`~slice.start`, diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f784d963f9d3e1..27aedfa878af9a 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -290,6 +290,7 @@ floating-point numbers. The same caveats apply as for floating-point numbers. The real and imaginary parts of a complex number ``z`` can be retrieved through the read-only attributes ``z.real`` and ``z.imag``. +.. _datamodel-sequences: Sequences --------- @@ -309,12 +310,25 @@ including built-in sequences, interpret negative subscripts by adding the sequence length. For example, ``a[-2]`` equals ``a[n-2]``, the second to last item of sequence a with length ``n``. -.. index:: single: slicing +The resulting value must be a nonnegative integer less than the number of items +in the sequence. If it is not, an :exc:`IndexError` is raised. -Sequences also support slicing: ``a[i:j]`` selects all items with index *k* such -that *i* ``<=`` *k* ``<`` *j*. When used as an expression, a slice is a -sequence of the same type. The comment above about negative indexes also applies +.. index:: + single: slicing + single: start (slice object attribute) + single: stop (slice object attribute) + single: step (slice object attribute) + +Sequences also support slicing: ``a[start:stop]`` selects all items with index *k* such +that *start* ``<=`` *k* ``<`` *stop*. When used as an expression, a slice is a +sequence of the same type. The comment above about negative subscripts also applies to negative slice positions. +Note that no error is raised if a slice position is less than zero or larger +than the length of the sequence. + +If *start* is missing or :data:`None`, slicing behaves as if *start* was zero. +If *stop* is missing or ``None``, slicing behaves as if *stop* was equal to +the length of the sequence. Some sequences also support "extended slicing" with a third "step" parameter: ``a[i:j:k]`` selects all items of *a* with index *x* where ``x = i + n*k``, *n* @@ -345,17 +359,22 @@ Strings pair: built-in function; chr pair: built-in function; ord single: character - single: integer + pair: string; item single: Unicode - A string is a sequence of values that represent Unicode code points. - All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:expr:`char` type; - instead, every code point in the string is represented as a string - object with length ``1``. The built-in function :func:`ord` + A string (:class:`str`) is a sequence of values that represent + :dfn:`characters`, or more formally, *Unicode code points*. + All the code points in the range ``0`` to ``0x10FFFF`` can be + represented in a string. + + Python doesn't have a dedicated *character* type. + Instead, every code point in the string is represented as a string + object with length ``1``. + + The built-in function :func:`ord` converts a code point from its string form to an integer in the - range ``0 - 10FFFF``; :func:`chr` converts an integer in the range - ``0 - 10FFFF`` to the corresponding length ``1`` string object. + range ``0`` to ``0x10FFFF``; :func:`chr` converts an integer in the range + ``0`` to ``0x10FFFF`` to the corresponding length ``1`` string object. :meth:`str.encode` can be used to convert a :class:`str` to :class:`bytes` using the given text encoding, and :meth:`bytes.decode` can be used to achieve the opposite. @@ -366,7 +385,7 @@ Tuples pair: singleton; tuple pair: empty; tuple - The items of a tuple are arbitrary Python objects. Tuples of two or + The items of a :class:`tuple` are arbitrary Python objects. Tuples of two or more items are formed by comma-separated lists of expressions. A tuple of one item (a 'singleton') can be formed by affixing a comma to an expression (an expression by itself does not create a tuple, since @@ -376,7 +395,7 @@ Tuples Bytes .. index:: bytes, byte - A bytes object is an immutable array. The items are 8-bit bytes, + A :class:`bytes` object is an immutable array. The items are 8-bit bytes, represented by integers in the range 0 <= x < 256. Bytes literals (like ``b'abc'``) and the built-in :func:`bytes` constructor can be used to create bytes objects. Also, bytes objects can be @@ -461,6 +480,8 @@ Frozen sets a dictionary key. +.. _datamodel-mappings: + Mappings -------- @@ -3217,28 +3238,39 @@ through the object's keys; for sequences, it should iterate through the values. and so forth. Missing slice items are always filled in with ``None``. -.. method:: object.__getitem__(self, key) +.. method:: object.__getitem__(self, subscript) + + Called to implement *subscription*, that is, ``self[subscript]``. + See :ref:`subscriptions` for details on the syntax. + + There are two types of built-in objects that support subscription + via :meth:`!__getitem__`: + + - **sequences**, where *subscript* (also called + :term:`index`) should be an integer or a :class:`slice` object. + See the :ref:`sequence documentation ` for the expected + behavior, including handling :class:`slice` objects and negative indices. + - **mappings**, where *subscript* is also called the :term:`key`. + See :ref:`mapping documentation ` for the expected + behavior. - Called to implement evaluation of ``self[key]``. For :term:`sequence` types, - the accepted keys should be integers. Optionally, they may support - :class:`slice` objects as well. Negative index support is also optional. - If *key* is - of an inappropriate type, :exc:`TypeError` may be raised; if *key* is a value - outside the set of indexes for the sequence (after any special - interpretation of negative values), :exc:`IndexError` should be raised. For - :term:`mapping` types, if *key* is missing (not in the container), - :exc:`KeyError` should be raised. + If *subscript* is of an inappropriate type, :meth:`!__getitem__` + should raise :exc:`TypeError`. + If *subscript* has an inappropriate value, :meth:`!__getitem__` + should raise an :exc:`LookupError` or one of its subclasses + (:exc:`IndexError` for sequences; :exc:`KeyError` for mappings). .. note:: - :keyword:`for` loops expect that an :exc:`IndexError` will be raised for - illegal indexes to allow proper detection of the end of the sequence. + The sequence iteration protocol (used, for example, in :keyword:`for` + loops), expects that an :exc:`IndexError` will be raised for illegal + indexes to allow proper detection of the end of a sequence. .. note:: - When :ref:`subscripting` a *class*, the special + When :ref:`subscripting ` a *class*, the special class method :meth:`~object.__class_getitem__` may be called instead of - ``__getitem__()``. See :ref:`classgetitem-versus-getitem` for more + :meth:`!__getitem__`. See :ref:`classgetitem-versus-getitem` for more details. diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 32f2d4596fe632..281d032b2a0f16 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -911,7 +911,7 @@ Primaries represent the most tightly bound operations of the language. Their syntax is: .. productionlist:: python-grammar - primary: `atom` | `attributeref` | `subscription` | `slicing` | `call` + primary: `atom` | `attributeref` | `subscription` | `call` .. _attribute-references: @@ -950,8 +950,8 @@ method, that method is called as a fallback. .. _subscriptions: -Subscriptions -------------- +Subscriptions and slicings +-------------------------- .. index:: single: subscription @@ -966,67 +966,74 @@ Subscriptions pair: object; dictionary pair: sequence; item -The subscription of an instance of a :ref:`container class ` -will generally select an element from the container. The subscription of a -:term:`generic class ` will generally return a -:ref:`GenericAlias ` object. +The :dfn:`subscription` syntax is usually used for selecting an element from a +:ref:`container ` -- for example, to get a value from +a :class:`dict`:: -.. productionlist:: python-grammar - subscription: `primary` "[" `flexible_expression_list` "]" - -When an object is subscripted, the interpreter will evaluate the primary and -the expression list. + >>> digits_by_name = {'one': 1, 'two': 2} + >>> digits_by_name['two'] # Subscripting a dictionary using the key 'two' + 2 -The primary must evaluate to an object that supports subscription. An object -may support subscription through defining one or both of -:meth:`~object.__getitem__` and :meth:`~object.__class_getitem__`. When the -primary is subscripted, the evaluated result of the expression list will be -passed to one of these methods. For more details on when ``__class_getitem__`` -is called instead of ``__getitem__``, see :ref:`classgetitem-versus-getitem`. +In the subscription syntax, the object being subscribed -- a +:ref:`primary ` -- is followed by a :dfn:`subscript` in +square brackets. +In the simplest case, the subscript is a single expression. + +Depending on the type of the object being subscribed, the subscript is +sometimes called a :term:`key` (for mappings), :term:`index` (for sequences), +or *type argument* (for :term:`generic types `). +Syntactically, these are all equivalent:: + + >>> colors = ['red', 'blue', 'green', 'black'] + >>> colors[3] # Subscripting a list using the index 3 + 'black' + + >>> list[str] # Parameterizing the list type using the type argument str + list[str] + +At runtime, the interpreter will evaluate the primary and +the subscript, and call the primary's :meth:`~object.__getitem__` or +:meth:`~object.__class_getitem__` :term:`special method` with the subscript +as argument. +For more details on which of these methods is called, see +:ref:`classgetitem-versus-getitem`. + +To show how subscription works, we can define a custom object that +implements :meth:`~object.__getitem__` and prints out the value of +the subscript:: + + >>> class SubscriptionDemo: + ... def __getitem__(self, key): + ... print(f'subscripted with: {key!r}') + ... + >>> demo = SubscriptionDemo() + >>> demo[1] + subscripted with: 1 + >>> demo['a' * 3] + subscripted with: 'aaa' -If the expression list contains at least one comma, or if any of the expressions -are starred, the expression list will evaluate to a :class:`tuple` containing -the items of the expression list. Otherwise, the expression list will evaluate -to the value of the list's sole member. +See :meth:`~object.__getitem__` documentation for how built-in types handle +subscription. -.. versionchanged:: 3.11 - Expressions in an expression list may be starred. See :pep:`646`. - -For built-in objects, there are two types of objects that support subscription -via :meth:`~object.__getitem__`: - -1. Mappings. If the primary is a :term:`mapping`, the expression list must - evaluate to an object whose value is one of the keys of the mapping, and the - subscription selects the value in the mapping that corresponds to that key. - An example of a builtin mapping class is the :class:`dict` class. -2. Sequences. If the primary is a :term:`sequence`, the expression list must - evaluate to an :class:`int` or a :class:`slice` (as discussed in the - following section). Examples of builtin sequence classes include the - :class:`str`, :class:`list` and :class:`tuple` classes. - -The formal syntax makes no special provision for negative indices in -:term:`sequences `. However, built-in sequences all provide a :meth:`~object.__getitem__` -method that interprets negative indices by adding the length of the sequence -to the index so that, for example, ``x[-1]`` selects the last item of ``x``. The -resulting value must be a nonnegative integer less than the number of items in -the sequence, and the subscription selects the item whose index is that value -(counting from zero). Since the support for negative indices and slicing -occurs in the object's :meth:`~object.__getitem__` method, subclasses overriding -this method will need to explicitly add that support. +Subscriptions may also be used as targets in :ref:`assignment ` or +:ref:`deletion ` statements. +In these cases, the interpreter will call the subscripted object's +:meth:`~object.__setitem__` or :meth:`~object.__delitem__` +:term:`special method`, respectively, instead of :meth:`~object.__getitem__`. -.. index:: - single: character - pair: string; item +.. code-block:: -A :class:`string ` is a special kind of sequence whose items are -*characters*. A character is not a separate data type but a -string of exactly one character. + >>> colors = ['red', 'blue', 'green', 'black'] + >>> colors[3] = 'white' # Setting item at index + >>> colors + ['red', 'blue', 'green', 'white'] + >>> del colors[3] # Deleting item at index 3 + >>> colors + ['red', 'blue', 'green'] +All advanced forms of *subscript* documented in the following sections +are also usable for assignment and deletion. -.. _slicings: - -Slicings --------- .. index:: single: slicing @@ -1040,43 +1047,111 @@ Slicings pair: object; tuple pair: object; list -A slicing selects a range of items in a sequence object (e.g., a string, tuple -or list). Slicings may be used as expressions or as targets in assignment or -:keyword:`del` statements. The syntax for a slicing: +.. _slicings: -.. productionlist:: python-grammar - slicing: `primary` "[" `slice_list` "]" - slice_list: `slice_item` ("," `slice_item`)* [","] - slice_item: `expression` | `proper_slice` - proper_slice: [`lower_bound`] ":" [`upper_bound`] [ ":" [`stride`] ] - lower_bound: `expression` - upper_bound: `expression` - stride: `expression` - -There is ambiguity in the formal syntax here: anything that looks like an -expression list also looks like a slice list, so any subscription can be -interpreted as a slicing. Rather than further complicating the syntax, this is -disambiguated by defining that in this case the interpretation as a subscription -takes priority over the interpretation as a slicing (this is the case if the -slice list contains no proper slice). +Slicings +^^^^^^^^ -.. index:: - single: start (slice object attribute) - single: stop (slice object attribute) - single: step (slice object attribute) - -The semantics for a slicing are as follows. The primary is indexed (using the -same :meth:`~object.__getitem__` method as -normal subscription) with a key that is constructed from the slice list, as -follows. If the slice list contains at least one comma, the key is a tuple -containing the conversion of the slice items; otherwise, the conversion of the -lone slice item is the key. The conversion of a slice item that is an -expression is that expression. The conversion of a proper slice is a slice -object (see section :ref:`types`) whose :attr:`~slice.start`, -:attr:`~slice.stop` and :attr:`~slice.step` attributes are the values of the -expressions given as lower bound, upper bound and stride, respectively, -substituting ``None`` for missing expressions. +A more advanced form of subscription, :dfn:`slicing`, is commonly used +to extract a portion of a :ref:`sequence `. +In this form, the subscript is a :term:`slice`: up to three +expressions separated by colons. +Any of the expressions may be omitted, but a slice must contain at least one +colon:: + + >>> number_names = ['zero', 'one', 'two', 'three', 'four', 'five'] + >>> number_names[1:3] + ['one', 'two'] + >>> number_names[1:] + ['one', 'two', 'three', 'four', 'five'] + >>> number_names[:3] + ['zero', 'one', 'two'] + >>> number_names[:] + ['zero', 'one', 'two', 'three', 'four', 'five'] + >>> number_names[::2] + ['zero', 'two', 'four'] + >>> number_names[:-3] + ['zero', 'one', 'two'] + >>> del number_names[4:] + >>> number_names + ['zero', 'one', 'two', 'three'] + +When a slice is evaluated, the interpreter constructs a :class:`slice` object +whose :attr:`~slice.start`, :attr:`~slice.stop` and +:attr:`~slice.step` attributes, respectively, are the results of the +expressions between the colons. +Any missing expression evaluates to :const:`None`. +This :class:`!slice` object is then passed to the :meth:`~object.__getitem__` +or :meth:`~object.__class_getitem__` :term:`special method`, as above. :: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[2:3] + subscripted with: slice(2, 3, None) + >>> demo[::'spam'] + subscripted with: slice(None, None, 'spam') + + +Comma-separated subscripts +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The subscript can also be given as two or more comma-separated expressions +or slices:: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[1, 2, 3] + subscripted with: (1, 2, 3) + >>> demo[1:2, 3] + subscripted with: (slice(1, 2, None), 3) + +This form is commonly used with numerical libraries for slicing +multi-dimensional data. +In this case, the interpreter constructs a :class:`tuple` of the results of the +expressions or slices, and passes this tuple to the :meth:`~object.__getitem__` +or :meth:`~object.__class_getitem__` :term:`special method`, as above. + +The subscript may also be given as a single expression or slice followed +by a comma, to specify a one-element tuple:: + + >>> demo['spam',] + subscripted with: ('spam',) + + +"Starred" subscriptions +^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.11 + Expressions in *tuple_slices* may be starred. See :pep:`646`. + +The subscript can also contain a starred expression. +In this case, the interpreter unpacks the result into a tuple, and passes +this tuple to :meth:`~object.__getitem__` or :meth:`~object.__class_getitem__`:: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[*range(10)] + subscripted with: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + +Starred expressions may be combined with comma-separated expressions +and slices:: + + >>> demo['a', 'b', *range(3), 'c'] + subscripted with: ('a', 'b', 0, 1, 2, 'c') + + +Formal subscription grammar +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. grammar-snippet:: + :group: python-grammar + + subscription: `primary` '[' `subscript` ']' + subscript: `single_subscript` | `tuple_subscript` + single_subscript: `proper_slice` | `assignment_expression` + proper_slice: [`expression`] ":" [`expression`] [ ":" [`expression`] ] + tuple_subscript: ','.(`single_subscript` | `starred_expression`)+ [','] +Recall that the ``|`` operator :ref:`denotes ordered choice `. +Specifically, in :token:`!subscript`, if both alternatives would match, the +first (:token:`!single_subscript`) has priority. .. index:: pair: object; callable @@ -2094,7 +2169,7 @@ precedence and have a left-to-right chaining feature as described in the | ``{key: value...}``, | dictionary display, | | ``{expressions...}`` | set display | +-----------------------------------------------+-------------------------------------+ -| ``x[index]``, ``x[index:index]``, | Subscription, slicing, | +| ``x[index]``, ``x[index:index]`` | Subscription (including slicing), | | ``x(arguments...)``, ``x.attribute`` | call, attribute reference | +-----------------------------------------------+-------------------------------------+ | :keyword:`await x ` | Await expression | diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 9c022570e7e847..643ca106548367 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -91,11 +91,10 @@ attributes or items of mutable objects: : | "[" [`target_list`] "]" : | `attributeref` : | `subscription` - : | `slicing` : | "*" `target` -(See section :ref:`primaries` for the syntax definitions for *attributeref*, -*subscription*, and *slicing*.) +(See section :ref:`primaries` for the syntax definitions for *attributeref* +and *subscription*.) An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and @@ -107,8 +106,8 @@ right. pair: target; list Assignment is defined recursively depending on the form of the target (list). -When a target is part of a mutable object (an attribute reference, subscription -or slicing), the mutable object must ultimately perform the assignment and +When a target is part of a mutable object (an attribute reference or +subscription), the mutable object must ultimately perform the assignment and decide about its validity, and may raise an exception if the assignment is unacceptable. The rules observed by various types and the exceptions raised are given with the definition of the object types (see section :ref:`types`). @@ -189,9 +188,14 @@ Assignment of an object to a single target is recursively defined as follows. pair: object; mutable * If the target is a subscription: The primary expression in the reference is - evaluated. It should yield either a mutable sequence object (such as a list) - or a mapping object (such as a dictionary). Next, the subscript expression is evaluated. + Next, the subscript expression is evaluated. + Then, the primary's :meth:`~object.__setitem__` method is called with + two arguments: the subscript and the assigned object. + + Typically, :meth:`~object.__setitem__` is defined on mutable sequence objects + (such as lists) and mapping objects (such as dictionaries), and behaves as + follows. .. index:: pair: object; sequence @@ -214,16 +218,13 @@ Assignment of an object to a single target is recursively defined as follows. object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed). - For user-defined objects, the :meth:`~object.__setitem__` method is called with - appropriate arguments. - .. index:: pair: slicing; assignment -* If the target is a slicing: The primary expression in the reference is - evaluated. It should yield a mutable sequence object (such as a list). The - assigned object should be a sequence object of the same type. Next, the lower - and upper bound expressions are evaluated, insofar they are present; defaults - are zero and the sequence's length. The bounds should evaluate to integers. + If the target is a slicing: The primary expression should evaluate to + a mutable sequence object (such as a list). + The assigned object should be :term:`iterable`. + The slicing's lower and upper bounds should be integers; if they are ``None`` + (or not present), the defaults are zero and the sequence's length. If either bound is negative, the sequence's length is added to it. The resulting bounds are clipped to lie between zero and the sequence's length, inclusive. Finally, the sequence object is asked to replace the slice with @@ -231,12 +232,6 @@ Assignment of an object to a single target is recursively defined as follows. from the length of the assigned sequence, thus changing the length of the target sequence, if the target sequence allows it. -.. impl-detail:: - - In the current implementation, the syntax for targets is taken to be the same - as for expressions, and invalid syntax is rejected during the code generation - phase, causing less detailed error messages. - Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are 'simultaneous' (for example ``a, b = b, a`` swaps two variables), overlaps *within* the collection of assigned-to @@ -281,7 +276,7 @@ operation and an assignment statement: .. productionlist:: python-grammar augmented_assignment_stmt: `augtarget` `augop` (`expression_list` | `yield_expression`) - augtarget: `identifier` | `attributeref` | `subscription` | `slicing` + augtarget: `identifier` | `attributeref` | `subscription` augop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" : | ">>=" | "<<=" | "&=" | "^=" | "|=" @@ -470,7 +465,7 @@ in the same code block. Trying to delete an unbound name raises a .. index:: pair: attribute; deletion -Deletion of attribute references, subscriptions and slicings is passed to the +Deletion of attribute references and subscriptions is passed to the primary object involved; deletion of a slicing is in general equivalent to assignment of an empty slice of the right type (but even this is determined by the sliced object). From 7c176918e16bf42f7e3edb30c90947a617c730e4 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 4 Feb 2026 11:43:47 -0500 Subject: [PATCH 05/13] gh-141004: Document remaining `pyport.h` utility macros (GH-144279) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner --- Doc/c-api/intro.rst | 96 ++++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 9 --- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 71ddaf0766c210..247d3df65123a6 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -167,6 +167,35 @@ complete listing. .. versionadded:: 3.3 +.. c:macro:: Py_ALIGNED(num) + + Specify alignment to *num* bytes on compilers that support it. + + Consider using the C11 standard ``_Alignas`` specifier over this macro. + +.. c:macro:: Py_ARITHMETIC_RIGHT_SHIFT(type, integer, positions) + + Similar to ``integer >> positions``, but forces sign extension, as the C + standard does not define whether a right-shift of a signed integer will + perform sign extension or a zero-fill. + + *integer* should be any signed integer type. + *positions* is the number of positions to shift to the right. + + Both *integer* and *positions* can be evaluated more than once; + consequently, avoid directly passing a function call or some other + operation with side-effects to this macro. Instead, store the result as a + variable and then pass it. + + *type* is unused and only kept for backwards compatibility. Historically, + *type* was used to cast *integer*. + + .. versionchanged:: 3.1 + + This macro is now valid for all signed integer types, not just those for + which ``unsigned type`` is legal. As a result, *type* is no longer + used. + .. c:macro:: Py_ALWAYS_INLINE Ask the compiler to always inline a static inline function. The compiler can @@ -189,6 +218,15 @@ complete listing. .. versionadded:: 3.11 +.. c:macro:: Py_CAN_START_THREADS + + If this macro is defined, then the current system is able to start threads. + + Currently, all systems supported by CPython (per :pep:`11`), with the + exception of some WebAssembly platforms, support starting threads. + + .. versionadded:: 3.13 + .. c:macro:: Py_CHARMASK(c) Argument must be a character or an integer in the range [-128, 127] or [0, @@ -206,11 +244,35 @@ complete listing. .. versionchanged:: 3.8 MSVC support was added. +.. c:macro:: Py_FORCE_EXPANSION(X) + + This is equivalent to ``X``, which is useful for token-pasting in + macros, as macro expansions in *X* are forcefully evaluated by the + preprocessor. + +.. c:macro:: Py_GCC_ATTRIBUTE(name) + + Use a GCC attribute *name*, hiding it from compilers that don't support GCC + attributes (such as MSVC). + + This expands to ``__attribute__((name))`` on a GCC compiler, and expands + to nothing on compilers that don't support GCC attributes. + .. c:macro:: Py_GETENV(s) Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the command line (see :c:member:`PyConfig.use_environment`). +.. c:macro:: Py_LL(number) + + Use *number* as a ``long long`` integer literal. + + This usally expands to *number* followed by ``LL``, but will expand to some + compiler-specific suffixes (such as ``I64``) on older compilers. + + In modern versions of Python, this macro is not very useful, as C99 and + later require the ``LL`` suffix to be valid for an integer. + .. c:macro:: Py_LOCAL(type) Declare a function returning the specified *type* using a fast-calling @@ -268,6 +330,22 @@ complete listing. .. versionadded:: 3.11 +.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller) + + Cast *value* to type *smaller* from type *larger*, validating that no + information was lost. + + On release builds of Python, this is roughly equivalent to + ``(smaller) value`` (in C++, ``static_cast(value)`` will be + used instead). + + On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts + that no information was lost with the cast from *larger* to *smaller*. + + *value*, *larger*, and *smaller* may all be evaluated more than once in the + expression; consequently, do not pass an expression with side-effects directly to + this macro. + .. c:macro:: Py_STRINGIFY(x) Convert ``x`` to a C string. E.g. ``Py_STRINGIFY(123)`` returns @@ -275,6 +353,14 @@ complete listing. .. versionadded:: 3.4 +.. c:macro:: Py_ULL(number) + + Similar to :c:macro:`Py_LL`, but *number* will be an ``unsigned long long`` + literal instead. This is done by appending ``U`` to the result of ``Py_LL``. + + In modern versions of Python, this macro is not very useful, as C99 and + later require the ``ULL``/``LLU`` suffixes to be valid for an integer. + .. c:macro:: Py_UNREACHABLE() Use this when you have a code path that cannot be reached by design. @@ -415,6 +501,16 @@ complete listing. This macro is intended for defining CPython's C API itself; extension modules should not use it for their own symbols. +.. c:macro:: Py_VA_COPY + + This is a :term:`soft deprecated` alias to the C99-standard ``va_copy`` + function. + + Historically, this would use a compiler-specific method to copy a ``va_list``. + + .. versionchanged:: 3.6 + This is now an alias to ``va_copy``. + .. _api-objects: diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index e0b2670808c79c..e628bdfebcbded 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -31,15 +31,6 @@ Py_TPFLAGS_IS_ABSTRACT PyExpat_CAPI_MAGIC PyExpat_CAPSULE_NAME # pyport.h -Py_ALIGNED -Py_ARITHMETIC_RIGHT_SHIFT -Py_CAN_START_THREADS -Py_FORCE_EXPANSION -Py_GCC_ATTRIBUTE -Py_LL -Py_SAFE_DOWNCAST -Py_ULL -Py_VA_COPY PYLONG_BITS_IN_DIGIT PY_DWORD_MAX PY_FORMAT_SIZE_T From 088b86a41021e8adf827308a1b7836a68b5d0e7a Mon Sep 17 00:00:00 2001 From: Adorilson Bezerra Date: Wed, 4 Feb 2026 17:17:42 +0000 Subject: [PATCH 06/13] gh-106318: Add examples for `str.startswith()` method (#144369) Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/library/stdtypes.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 99479091cd5bd2..0f20163e69509c 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2751,6 +2751,19 @@ expression support in the :mod:`re` module). test string beginning at that position. With optional *end*, stop comparing string at that position. + For example: + + .. doctest:: + + >>> 'Python'.startswith('Py') + True + >>> 'a tuple of prefixes'.startswith(('at', 'a')) + True + >>> 'Python is amazing'.startswith('is', 7) + True + + See also :meth:`endswith` and :meth:`removeprefix`. + .. method:: str.strip(chars=None, /) From 2032b38bc14ccf1d7470d4b648b49cd89fe4ed81 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 4 Feb 2026 19:23:09 +0200 Subject: [PATCH 07/13] gh-143962: Improve name suggestions for not normalized names (GH-144154) Suggest the normalized name or the closest name to the normalized name. If the suggested name is not ASCII, include also its ASCII representation. --- Lib/test/test_traceback.py | 46 +++++++++++++++++++ Lib/traceback.py | 21 ++++++++- ...-01-22-17-04-30.gh-issue-143962.dQR1a9.rst | 3 ++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 96510eeec54640..a4a49fd44bb2e0 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4250,6 +4250,24 @@ def __dir__(self): actual = self.get_suggestion(A(), 'blech') self.assertNotIn("Did you mean", actual) + def test_suggestions_not_normalized(self): + class A: + analization = None + fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = None + + suggestion = self.get_suggestion(A(), 'fiⁿₐˡᵢᶻₐᵗᵢᵒₙ') + self.assertIn("'finalization'", suggestion) + self.assertNotIn("analization", suggestion) + + class B: + attr_a = None + attr_µ = None # attr_\xb5 + + suggestion = self.get_suggestion(B(), 'attr_\xb5') + self.assertIn("'attr_\u03bc'", suggestion) + self.assertIn(r"'attr_\u03bc'", suggestion) + self.assertNotIn("attr_a", suggestion) + class GetattrSuggestionTests(BaseSuggestionTests): def test_suggestions_no_args(self): @@ -4872,6 +4890,34 @@ def foo(self): actual = self.get_suggestion(instance.foo) self.assertIn("self.blech", actual) + def test_name_error_with_instance_not_normalized(self): + class A: + def __init__(self): + self.fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = None + def foo(self): + analization = 1 + x = fiⁿₐˡᵢᶻₐᵗᵢᵒₙ + + instance = A() + actual = self.get_suggestion(instance.foo) + self.assertIn("self.finalization", actual) + self.assertNotIn("fiⁿₐˡᵢᶻₐᵗᵢᵒₙ", actual) + self.assertNotIn("analization", actual) + + class B: + def __init__(self): + self.attr_µ = None # attr_\xb5 + def foo(self): + attr_a = 1 + x = attr_µ # attr_\xb5 + + instance = B() + actual = self.get_suggestion(instance.foo) + self.assertIn("self.attr_\u03bc", actual) + self.assertIn(r"self.attr_\u03bc", actual) + self.assertNotIn("attr_\xb5", actual) + self.assertNotIn("attr_a", actual) + def test_unbound_local_error_with_instance(self): class A: def __init__(self): diff --git a/Lib/traceback.py b/Lib/traceback.py index f95d6bdbd016ac..97d83f3ddd3297 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1111,7 +1111,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, wrong_name = getattr(exc_value, "name_from", None) suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: - self._str += f". Did you mean: '{suggestion}'?" + if suggestion.isascii(): + self._str += f". Did you mean: '{suggestion}'?" + else: + self._str += f". Did you mean: '{suggestion}' ({suggestion!a})?" elif exc_type and issubclass(exc_type, ModuleNotFoundError): module_name = getattr(exc_value, "name", None) if module_name in sys.stdlib_module_names: @@ -1129,7 +1132,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, wrong_name = getattr(exc_value, "name", None) suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: - self._str += f". Did you mean: '{suggestion}'?" + if suggestion.isascii(): + self._str += f". Did you mean: '{suggestion}'?" + else: + self._str += f". Did you mean: '{suggestion}' ({suggestion!a})?" if issubclass(exc_type, NameError): wrong_name = getattr(exc_value, "name", None) if wrong_name is not None and wrong_name in sys.stdlib_module_names: @@ -1654,6 +1660,13 @@ def _check_for_nested_attribute(obj, wrong_name, attrs): def _compute_suggestion_error(exc_value, tb, wrong_name): if wrong_name is None or not isinstance(wrong_name, str): return None + not_normalized = False + if not wrong_name.isascii(): + from unicodedata import normalize + normalized_name = normalize('NFKC', wrong_name) + if normalized_name != wrong_name: + not_normalized = True + wrong_name = normalized_name if isinstance(exc_value, AttributeError): obj = exc_value.obj try: @@ -1699,6 +1712,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): + list(frame.f_builtins) ) d = [x for x in d if isinstance(x, str)] + if not_normalized and wrong_name in d: + return wrong_name # Check first if we are in a method and the instance # has the wrong name as attribute @@ -1711,6 +1726,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): if has_wrong_name: return f"self.{wrong_name}" + if not_normalized and wrong_name in d: + return wrong_name try: import _suggestions except ImportError: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst new file mode 100644 index 00000000000000..71c2476c02b89d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst @@ -0,0 +1,3 @@ +Name suggestion for not normalized name suggests now the normalized name or +the closest name to the normalized name. If the suggested name is not ASCII, +include also its ASCII representation. From ca530a4ff3bfe632fcf80d1866d27c7f78604f37 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 4 Feb 2026 19:38:45 +0100 Subject: [PATCH 08/13] gh-123471: Make concurrent iteration over `itertools.permutations` and `itertools.combinations_with_replacement` thread-safe (gh-144402) --- .../test_free_threading/test_itertools.py | 107 ++++++------------ ...-02-03-08-50-58.gh-issue-123471.yF1Gym.rst | 1 + Modules/itertoolsmodule.c | 24 +++- 3 files changed, 59 insertions(+), 73 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-03-08-50-58.gh-issue-123471.yF1Gym.rst diff --git a/Lib/test/test_free_threading/test_itertools.py b/Lib/test/test_free_threading/test_itertools.py index 9d366041917bb3..bb6047e8669475 100644 --- a/Lib/test/test_free_threading/test_itertools.py +++ b/Lib/test/test_free_threading/test_itertools.py @@ -1,94 +1,59 @@ import unittest -from threading import Thread, Barrier -from itertools import batched, chain, cycle +from itertools import batched, chain, combinations_with_replacement, cycle, permutations from test.support import threading_helper threading_helper.requires_working_threading(module=True) -class ItertoolsThreading(unittest.TestCase): - - @threading_helper.reap_threads - def test_batched(self): - number_of_threads = 10 - number_of_iterations = 20 - barrier = Barrier(number_of_threads) - def work(it): - barrier.wait() - while True: - try: - next(it) - except StopIteration: - break - data = tuple(range(1000)) - for it in range(number_of_iterations): - batch_iterator = batched(data, 2) - worker_threads = [] - for ii in range(number_of_threads): - worker_threads.append( - Thread(target=work, args=[batch_iterator])) +def work_iterator(it): + while True: + try: + next(it) + except StopIteration: + break - with threading_helper.start_threads(worker_threads): - pass - barrier.reset() +class ItertoolsThreading(unittest.TestCase): @threading_helper.reap_threads - def test_cycle(self): - number_of_threads = 6 + def test_batched(self): number_of_iterations = 10 - number_of_cycles = 400 + for _ in range(number_of_iterations): + it = batched(tuple(range(1000)), 2) + threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it]) - barrier = Barrier(number_of_threads) + @threading_helper.reap_threads + def test_cycle(self): def work(it): - barrier.wait() - for _ in range(number_of_cycles): - try: - next(it) - except StopIteration: - pass + for _ in range(400): + next(it) - data = (1, 2, 3, 4) - for it in range(number_of_iterations): - cycle_iterator = cycle(data) - worker_threads = [] - for ii in range(number_of_threads): - worker_threads.append( - Thread(target=work, args=[cycle_iterator])) - - with threading_helper.start_threads(worker_threads): - pass - - barrier.reset() + number_of_iterations = 6 + for _ in range(number_of_iterations): + it = cycle((1, 2, 3, 4)) + threading_helper.run_concurrently(work, nthreads=6, args=[it]) @threading_helper.reap_threads def test_chain(self): - number_of_threads = 6 - number_of_iterations = 20 - - barrier = Barrier(number_of_threads) - def work(it): - barrier.wait() - while True: - try: - next(it) - except StopIteration: - break - - data = [(1, )] * 200 - for it in range(number_of_iterations): - chain_iterator = chain(*data) - worker_threads = [] - for ii in range(number_of_threads): - worker_threads.append( - Thread(target=work, args=[chain_iterator])) - - with threading_helper.start_threads(worker_threads): - pass + number_of_iterations = 10 + for _ in range(number_of_iterations): + it = chain(*[(1,)] * 200) + threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) - barrier.reset() + @threading_helper.reap_threads + def test_combinations_with_replacement(self): + number_of_iterations = 6 + for _ in range(number_of_iterations): + it = combinations_with_replacement(tuple(range(2)), 2) + threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) + @threading_helper.reap_threads + def test_permutations(self): + number_of_iterations = 6 + for _ in range(number_of_iterations): + it = permutations(tuple(range(4)), 2) + threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it]) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Library/2026-02-03-08-50-58.gh-issue-123471.yF1Gym.rst b/Misc/NEWS.d/next/Library/2026-02-03-08-50-58.gh-issue-123471.yF1Gym.rst new file mode 100644 index 00000000000000..85e9a03426e1fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-03-08-50-58.gh-issue-123471.yF1Gym.rst @@ -0,0 +1 @@ +Make concurrent iteration over :class:`itertools.combinations_with_replacement` and :class:`itertools.permutations` safe under free-threading. diff --git a/Modules/itertoolsmodule.c b/Modules/itertoolsmodule.c index 8685eff8be65c3..7e73f76bc20b58 100644 --- a/Modules/itertoolsmodule.c +++ b/Modules/itertoolsmodule.c @@ -2587,7 +2587,7 @@ cwr_traverse(PyObject *op, visitproc visit, void *arg) } static PyObject * -cwr_next(PyObject *op) +cwr_next_lock_held(PyObject *op) { cwrobject *co = cwrobject_CAST(op); PyObject *elem; @@ -2666,6 +2666,16 @@ cwr_next(PyObject *op) return NULL; } +static PyObject * +cwr_next(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = cwr_next_lock_held(op); + Py_END_CRITICAL_SECTION() + return result; +} + static PyMethodDef cwr_methods[] = { {"__sizeof__", cwr_sizeof, METH_NOARGS, sizeof_doc}, {NULL, NULL} /* sentinel */ @@ -2846,7 +2856,7 @@ permutations_traverse(PyObject *op, visitproc visit, void *arg) } static PyObject * -permutations_next(PyObject *op) +permutations_next_lock_held(PyObject *op) { permutationsobject *po = permutationsobject_CAST(op); PyObject *elem; @@ -2936,6 +2946,16 @@ permutations_next(PyObject *op) return NULL; } +static PyObject * +permutations_next(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = permutations_next_lock_held(op); + Py_END_CRITICAL_SECTION() + return result; +} + static PyMethodDef permuations_methods[] = { {"__sizeof__", permutations_sizeof, METH_NOARGS, sizeof_doc}, {NULL, NULL} /* sentinel */ From ad344ca309fd0b46ebb90eb978b6845c22811643 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 4 Feb 2026 14:21:20 -0600 Subject: [PATCH 09/13] Itertools recipes: Replace the tabulate() example with running_mean() (gh-144483) --- Doc/library/itertools.rst | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst index 08dacb505f7748..4f73a74bdd17e2 100644 --- a/Doc/library/itertools.rst +++ b/Doc/library/itertools.rst @@ -845,7 +845,8 @@ and :term:`generators ` which incur interpreter overhead. from contextlib import suppress from functools import reduce from math import comb, isqrt, prod, sumprod - from operator import getitem, is_not, itemgetter, mul, neg + from operator import getitem, is_not, itemgetter, mul, neg, truediv + # ==== Basic one liners ==== @@ -858,9 +859,10 @@ and :term:`generators ` which incur interpreter overhead. # prepend(1, [2, 3, 4]) → 1 2 3 4 return chain([value], iterable) - def tabulate(function, start=0): - "Return function(0), function(1), ..." - return map(function, count(start)) + def running_mean(iterable): + "Yield the average of all values seen so far." + # running_mean([8.5, 9.5, 7.5, 6.5]) -> 8.5 9.0 8.5 8.0 + return map(truediv, accumulate(iterable), count(1)) def repeatfunc(function, times=None, *args): "Repeat calls to a function with specified arguments." @@ -913,6 +915,7 @@ and :term:`generators ` which incur interpreter overhead. # all_equal('4٤௪౪໔', key=int) → True return len(take(2, groupby(iterable, key))) <= 1 + # ==== Data pipelines ==== def unique_justseen(iterable, key=None): @@ -1021,6 +1024,7 @@ and :term:`generators ` which incur interpreter overhead. while True: yield function() + # ==== Mathematical operations ==== def multinomial(*counts): @@ -1040,6 +1044,7 @@ and :term:`generators ` which incur interpreter overhead. # sum_of_squares([10, 20, 30]) → 1400 return sumprod(*tee(iterable)) + # ==== Matrix operations ==== def reshape(matrix, columns): @@ -1058,6 +1063,7 @@ and :term:`generators ` which incur interpreter overhead. n = len(m2[0]) return batched(starmap(sumprod, product(m1, transpose(m2))), n) + # ==== Polynomial arithmetic ==== def convolve(signal, kernel): @@ -1114,6 +1120,7 @@ and :term:`generators ` which incur interpreter overhead. powers = reversed(range(1, n)) return list(map(mul, coefficients, powers)) + # ==== Number theory ==== def sieve(n): @@ -1230,8 +1237,8 @@ and :term:`generators ` which incur interpreter overhead. [(0, 'a'), (1, 'b'), (2, 'c')] - >>> list(islice(tabulate(lambda x: 2*x), 4)) - [0, 2, 4, 6] + >>> list(running_mean([8.5, 9.5, 7.5, 6.5])) + [8.5, 9.0, 8.5, 8.0] >>> for _ in loops(5): @@ -1798,6 +1805,10 @@ and :term:`generators ` which incur interpreter overhead. # Old recipes and their tests which are guaranteed to continue to work. + def tabulate(function, start=0): + "Return function(0), function(1), ..." + return map(function, count(start)) + def old_sumprod_recipe(vec1, vec2): "Compute a sum of products." return sum(starmap(operator.mul, zip(vec1, vec2, strict=True))) @@ -1877,6 +1888,10 @@ and :term:`generators ` which incur interpreter overhead. .. doctest:: :hide: + >>> list(islice(tabulate(lambda x: 2*x), 4)) + [0, 2, 4, 6] + + >>> dotproduct([1,2,3], [4,5,6]) 32 From cc6697f90998723a72a986d4b40948a8a8af5569 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 5 Feb 2026 08:58:41 +0000 Subject: [PATCH 10/13] GH-144179: Use recorded values to make optimizer more robust (GH-144437) * Add three new symbol kinds * Do not smuggle code object in _PUSH_FRAME operand * Fix small bug in predicate analysis --- Include/internal/pycore_opcode_metadata.h | 22 +- Include/internal/pycore_optimizer.h | 14 + Include/internal/pycore_optimizer_types.h | 24 + Include/internal/pycore_uop_ids.h | 2020 +++++++++++---------- Include/internal/pycore_uop_metadata.h | 31 +- Lib/test/test_capi/test_opt.py | 44 - Modules/_testinternalcapi/test_cases.c.h | 139 +- Python/bytecodes.c | 52 +- Python/executor_cases.c.h | 109 +- Python/generated_cases.c.h | 139 +- Python/optimizer.c | 27 +- Python/optimizer_analysis.c | 31 +- Python/optimizer_bytecodes.c | 173 +- Python/optimizer_cases.c.h | 170 +- Python/optimizer_symbols.c | 527 +++++- Python/record_functions.c.h | 47 +- 16 files changed, 2062 insertions(+), 1507 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index db28839a860008..98d9c2b51a7834 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1179,7 +1179,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, - [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, @@ -1280,10 +1280,10 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [RESERVED] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, - [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, - [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SET_ADD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [SET_FUNCTION_ATTRIBUTE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, @@ -1320,7 +1320,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1354,7 +1354,7 @@ _PyOpcode_macro_expansion[256] = { [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_DICT] = { .nuops = 4, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_TOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_COMPACT_ASCII, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } }, @@ -1424,7 +1424,7 @@ _PyOpcode_macro_expansion[256] = { [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, OPARG_SIMPLE, 0 } } }, [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { _FORMAT_WITH_SPEC, OPARG_SIMPLE, 0 } } }, [FOR_ITER] = { .nuops = 1, .uops = { { _FOR_ITER, OPARG_REPLACED, 0 } } }, - [FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, + [FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } }, [FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } }, [FOR_ITER_TUPLE] = { .nuops = 3, .uops = { { _ITER_CHECK_TUPLE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_TUPLE, OPARG_REPLACED, 1 }, { _ITER_NEXT_TUPLE, OPARG_SIMPLE, 1 } } }, @@ -1494,9 +1494,9 @@ _PyOpcode_macro_expansion[256] = { [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { _PUSH_EXC_INFO, OPARG_SIMPLE, 0 } } }, [PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, OPARG_SIMPLE, 0 } } }, [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 0 } } }, - [RETURN_GENERATOR] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } }, - [RETURN_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } }, - [SEND_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, + [RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } }, + [RETURN_VALUE] = { .nuops = 1, .uops = { { _RETURN_VALUE, OPARG_SIMPLE, 0 } } }, + [SEND_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, OPARG_SIMPLE, 0 } } }, [SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, OPARG_SIMPLE, 0 } } }, [SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, OPARG_SIMPLE, 0 } } }, @@ -1532,7 +1532,7 @@ _PyOpcode_macro_expansion[256] = { [UNPACK_SEQUENCE_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 } } }, [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { _WITH_EXCEPT_START, OPARG_SIMPLE, 0 } } }, - [YIELD_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _YIELD_VALUE, OPARG_SIMPLE, 0 } } }, + [YIELD_VALUE] = { .nuops = 1, .uops = { { _YIELD_VALUE, OPARG_SIMPLE, 0 } } }, }; #endif // NEED_OPCODE_METADATA diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index bb2028c59356b2..79a2d60eb788ea 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -298,6 +298,11 @@ extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx); extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym); extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind); extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true); +extern void _Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef sym, PyObject *value); +extern void _Py_uop_sym_set_recorded_type(JitOptContext *ctx, JitOptRef sym, PyTypeObject *type); +extern void _Py_uop_sym_set_recorded_gen_func(JitOptContext *ctx, JitOptRef ref, PyFunctionObject *value); +extern PyCodeObject *_Py_uop_sym_get_probable_func_code(JitOptRef sym); +extern PyObject *_Py_uop_sym_get_probable_value(JitOptRef sym); extern void _Py_uop_abstractcontext_init(JitOptContext *ctx); extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx); @@ -308,6 +313,14 @@ extern _Py_UOpsAbstractFrame *_Py_uop_frame_new( int curr_stackentries, JitOptRef *args, int arg_len); + +extern _Py_UOpsAbstractFrame *_Py_uop_frame_new_from_symbol( + JitOptContext *ctx, + JitOptRef callable, + int curr_stackentries, + JitOptRef *args, + int arg_len); + extern int _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries); PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored); @@ -341,6 +354,7 @@ _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, int oparg, _PyExecutorObject *current_executor); PyAPI_FUNC(void) _PyJit_FinalizeTracing(PyThreadState *tstate, int err); +void _PyPrintExecutor(_PyExecutorObject *executor, const _PyUOpInstruction *marker); void _PyJit_TracerFree(_PyThreadStateImpl *_tstate); void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj); diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index b4b93e8353812a..57c0c828c2aabd 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -41,6 +41,9 @@ typedef enum _JitSymType { JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, JIT_SYM_PREDICATE_TAG = 11, + JIT_SYM_RECORDED_VALUE_TAG = 12, + JIT_SYM_RECORDED_TYPE_TAG = 13, + JIT_SYM_RECORDED_GEN_FUNC_TAG = 14, } JitSymType; typedef struct _jit_opt_known_class { @@ -87,6 +90,24 @@ typedef struct { uint16_t rhs; } JitOptPredicate; +typedef struct _jit_opt_recorded_value { + uint8_t tag; + bool known_type; + PyObject *value; +} JitOptRecordedValue; + +typedef struct _jit_opt_recorded_type { + uint8_t tag; + PyTypeObject *type; +} JitOptRecordedType; + +/* Represents a generator, but we record the + * function as the generator is emphemeral */ +typedef struct _jit_opt_recorded_gen_func { + uint8_t tag; + PyFunctionObject *func; +} JitOptRecordedGenFunc; + typedef struct { uint8_t tag; } JitOptCompactInt; @@ -100,6 +121,9 @@ typedef union _jit_opt_symbol { JitOptTruthiness truthiness; JitOptCompactInt compact; JitOptPredicate predicate; + JitOptRecordedValue recorded_value; + JitOptRecordedType recorded_type; + JitOptRecordedGenFunc recorded_gen_func; } JitOptSymbol; // This mimics the _PyStackRef API diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 850ae446dc7aca..f9313621756b45 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -147,57 +147,58 @@ extern "C" { #define _GUARD_CALLABLE_STR_1 402 #define _GUARD_CALLABLE_TUPLE_1 403 #define _GUARD_CALLABLE_TYPE_1 404 -#define _GUARD_DORV_NO_DICT 405 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 406 -#define _GUARD_GLOBALS_VERSION 407 -#define _GUARD_IP_RETURN_GENERATOR 408 -#define _GUARD_IP_RETURN_VALUE 409 -#define _GUARD_IP_YIELD_VALUE 410 -#define _GUARD_IP__PUSH_FRAME 411 -#define _GUARD_IS_FALSE_POP 412 -#define _GUARD_IS_NONE_POP 413 -#define _GUARD_IS_NOT_NONE_POP 414 -#define _GUARD_IS_TRUE_POP 415 -#define _GUARD_KEYS_VERSION 416 -#define _GUARD_NOS_COMPACT_ASCII 417 -#define _GUARD_NOS_DICT 418 -#define _GUARD_NOS_FLOAT 419 -#define _GUARD_NOS_INT 420 -#define _GUARD_NOS_LIST 421 -#define _GUARD_NOS_NOT_NULL 422 -#define _GUARD_NOS_NULL 423 -#define _GUARD_NOS_OVERFLOWED 424 -#define _GUARD_NOS_TUPLE 425 -#define _GUARD_NOS_UNICODE 426 -#define _GUARD_NOT_EXHAUSTED_LIST 427 -#define _GUARD_NOT_EXHAUSTED_RANGE 428 -#define _GUARD_NOT_EXHAUSTED_TUPLE 429 -#define _GUARD_THIRD_NULL 430 -#define _GUARD_TOS_ANY_SET 431 -#define _GUARD_TOS_DICT 432 -#define _GUARD_TOS_FLOAT 433 -#define _GUARD_TOS_INT 434 -#define _GUARD_TOS_LIST 435 -#define _GUARD_TOS_OVERFLOWED 436 -#define _GUARD_TOS_SLICE 437 -#define _GUARD_TOS_TUPLE 438 -#define _GUARD_TOS_UNICODE 439 -#define _GUARD_TYPE_VERSION 440 -#define _GUARD_TYPE_VERSION_AND_LOCK 441 -#define _HANDLE_PENDING_AND_DEOPT 442 +#define _GUARD_CODE 405 +#define _GUARD_DORV_NO_DICT 406 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 407 +#define _GUARD_GLOBALS_VERSION 408 +#define _GUARD_IP_RETURN_GENERATOR 409 +#define _GUARD_IP_RETURN_VALUE 410 +#define _GUARD_IP_YIELD_VALUE 411 +#define _GUARD_IP__PUSH_FRAME 412 +#define _GUARD_IS_FALSE_POP 413 +#define _GUARD_IS_NONE_POP 414 +#define _GUARD_IS_NOT_NONE_POP 415 +#define _GUARD_IS_TRUE_POP 416 +#define _GUARD_KEYS_VERSION 417 +#define _GUARD_NOS_COMPACT_ASCII 418 +#define _GUARD_NOS_DICT 419 +#define _GUARD_NOS_FLOAT 420 +#define _GUARD_NOS_INT 421 +#define _GUARD_NOS_LIST 422 +#define _GUARD_NOS_NOT_NULL 423 +#define _GUARD_NOS_NULL 424 +#define _GUARD_NOS_OVERFLOWED 425 +#define _GUARD_NOS_TUPLE 426 +#define _GUARD_NOS_UNICODE 427 +#define _GUARD_NOT_EXHAUSTED_LIST 428 +#define _GUARD_NOT_EXHAUSTED_RANGE 429 +#define _GUARD_NOT_EXHAUSTED_TUPLE 430 +#define _GUARD_THIRD_NULL 431 +#define _GUARD_TOS_ANY_SET 432 +#define _GUARD_TOS_DICT 433 +#define _GUARD_TOS_FLOAT 434 +#define _GUARD_TOS_INT 435 +#define _GUARD_TOS_LIST 436 +#define _GUARD_TOS_OVERFLOWED 437 +#define _GUARD_TOS_SLICE 438 +#define _GUARD_TOS_TUPLE 439 +#define _GUARD_TOS_UNICODE 440 +#define _GUARD_TYPE_VERSION 441 +#define _GUARD_TYPE_VERSION_AND_LOCK 442 +#define _HANDLE_PENDING_AND_DEOPT 443 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 443 -#define _INIT_CALL_PY_EXACT_ARGS 444 -#define _INIT_CALL_PY_EXACT_ARGS_0 445 -#define _INIT_CALL_PY_EXACT_ARGS_1 446 -#define _INIT_CALL_PY_EXACT_ARGS_2 447 -#define _INIT_CALL_PY_EXACT_ARGS_3 448 -#define _INIT_CALL_PY_EXACT_ARGS_4 449 -#define _INSERT_1_LOAD_CONST_INLINE 450 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW 451 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW 452 -#define _INSERT_NULL 453 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 444 +#define _INIT_CALL_PY_EXACT_ARGS 445 +#define _INIT_CALL_PY_EXACT_ARGS_0 446 +#define _INIT_CALL_PY_EXACT_ARGS_1 447 +#define _INIT_CALL_PY_EXACT_ARGS_2 448 +#define _INIT_CALL_PY_EXACT_ARGS_3 449 +#define _INIT_CALL_PY_EXACT_ARGS_4 450 +#define _INSERT_1_LOAD_CONST_INLINE 451 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW 452 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW 453 +#define _INSERT_NULL 454 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -207,133 +208,134 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 454 -#define _IS_OP 455 -#define _ITER_CHECK_LIST 456 -#define _ITER_CHECK_RANGE 457 -#define _ITER_CHECK_TUPLE 458 -#define _ITER_JUMP_LIST 459 -#define _ITER_JUMP_RANGE 460 -#define _ITER_JUMP_TUPLE 461 -#define _ITER_NEXT_LIST 462 -#define _ITER_NEXT_LIST_TIER_TWO 463 -#define _ITER_NEXT_RANGE 464 -#define _ITER_NEXT_TUPLE 465 +#define _IS_NONE 455 +#define _IS_OP 456 +#define _ITER_CHECK_LIST 457 +#define _ITER_CHECK_RANGE 458 +#define _ITER_CHECK_TUPLE 459 +#define _ITER_JUMP_LIST 460 +#define _ITER_JUMP_RANGE 461 +#define _ITER_JUMP_TUPLE 462 +#define _ITER_NEXT_LIST 463 +#define _ITER_NEXT_LIST_TIER_TWO 464 +#define _ITER_NEXT_RANGE 465 +#define _ITER_NEXT_TUPLE 466 #define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT -#define _JUMP_TO_TOP 466 +#define _JUMP_TO_TOP 467 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 467 -#define _LOAD_ATTR_CLASS 468 +#define _LOAD_ATTR 468 +#define _LOAD_ATTR_CLASS 469 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 469 -#define _LOAD_ATTR_METHOD_LAZY_DICT 470 -#define _LOAD_ATTR_METHOD_NO_DICT 471 -#define _LOAD_ATTR_METHOD_WITH_VALUES 472 -#define _LOAD_ATTR_MODULE 473 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 474 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 475 -#define _LOAD_ATTR_PROPERTY_FRAME 476 -#define _LOAD_ATTR_SLOT 477 -#define _LOAD_ATTR_WITH_HINT 478 +#define _LOAD_ATTR_INSTANCE_VALUE 470 +#define _LOAD_ATTR_METHOD_LAZY_DICT 471 +#define _LOAD_ATTR_METHOD_NO_DICT 472 +#define _LOAD_ATTR_METHOD_WITH_VALUES 473 +#define _LOAD_ATTR_MODULE 474 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 475 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 476 +#define _LOAD_ATTR_PROPERTY_FRAME 477 +#define _LOAD_ATTR_SLOT 478 +#define _LOAD_ATTR_WITH_HINT 479 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 479 +#define _LOAD_BYTECODE 480 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 480 -#define _LOAD_CONST_INLINE_BORROW 481 -#define _LOAD_CONST_UNDER_INLINE 482 -#define _LOAD_CONST_UNDER_INLINE_BORROW 483 +#define _LOAD_CONST_INLINE 481 +#define _LOAD_CONST_INLINE_BORROW 482 +#define _LOAD_CONST_UNDER_INLINE 483 +#define _LOAD_CONST_UNDER_INLINE_BORROW 484 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 484 -#define _LOAD_FAST_0 485 -#define _LOAD_FAST_1 486 -#define _LOAD_FAST_2 487 -#define _LOAD_FAST_3 488 -#define _LOAD_FAST_4 489 -#define _LOAD_FAST_5 490 -#define _LOAD_FAST_6 491 -#define _LOAD_FAST_7 492 +#define _LOAD_FAST 485 +#define _LOAD_FAST_0 486 +#define _LOAD_FAST_1 487 +#define _LOAD_FAST_2 488 +#define _LOAD_FAST_3 489 +#define _LOAD_FAST_4 490 +#define _LOAD_FAST_5 491 +#define _LOAD_FAST_6 492 +#define _LOAD_FAST_7 493 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 493 -#define _LOAD_FAST_BORROW_0 494 -#define _LOAD_FAST_BORROW_1 495 -#define _LOAD_FAST_BORROW_2 496 -#define _LOAD_FAST_BORROW_3 497 -#define _LOAD_FAST_BORROW_4 498 -#define _LOAD_FAST_BORROW_5 499 -#define _LOAD_FAST_BORROW_6 500 -#define _LOAD_FAST_BORROW_7 501 +#define _LOAD_FAST_BORROW 494 +#define _LOAD_FAST_BORROW_0 495 +#define _LOAD_FAST_BORROW_1 496 +#define _LOAD_FAST_BORROW_2 497 +#define _LOAD_FAST_BORROW_3 498 +#define _LOAD_FAST_BORROW_4 499 +#define _LOAD_FAST_BORROW_5 500 +#define _LOAD_FAST_BORROW_6 501 +#define _LOAD_FAST_BORROW_7 502 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 502 -#define _LOAD_GLOBAL_BUILTINS 503 -#define _LOAD_GLOBAL_MODULE 504 +#define _LOAD_GLOBAL 503 +#define _LOAD_GLOBAL_BUILTINS 504 +#define _LOAD_GLOBAL_MODULE 505 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 505 -#define _LOAD_SMALL_INT_0 506 -#define _LOAD_SMALL_INT_1 507 -#define _LOAD_SMALL_INT_2 508 -#define _LOAD_SMALL_INT_3 509 -#define _LOAD_SPECIAL 510 +#define _LOAD_SMALL_INT 506 +#define _LOAD_SMALL_INT_0 507 +#define _LOAD_SMALL_INT_1 508 +#define _LOAD_SMALL_INT_2 509 +#define _LOAD_SMALL_INT_3 510 +#define _LOAD_SPECIAL 511 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 511 +#define _MAKE_CALLARGS_A_TUPLE 512 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 512 +#define _MAKE_WARM 513 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 513 -#define _MAYBE_EXPAND_METHOD_KW 514 -#define _MONITOR_CALL 515 -#define _MONITOR_CALL_KW 516 -#define _MONITOR_JUMP_BACKWARD 517 -#define _MONITOR_RESUME 518 +#define _MAYBE_EXPAND_METHOD 514 +#define _MAYBE_EXPAND_METHOD_KW 515 +#define _MONITOR_CALL 516 +#define _MONITOR_CALL_KW 517 +#define _MONITOR_JUMP_BACKWARD 518 +#define _MONITOR_RESUME 519 #define _NOP NOP -#define _POP_CALL 519 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW 520 -#define _POP_CALL_ONE 521 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 522 -#define _POP_CALL_TWO 523 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 524 +#define _POP_CALL 520 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW 521 +#define _POP_CALL_ONE 522 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 523 +#define _POP_CALL_TWO 524 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 525 #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 525 -#define _POP_JUMP_IF_TRUE 526 +#define _POP_JUMP_IF_FALSE 526 +#define _POP_JUMP_IF_TRUE 527 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 527 -#define _POP_TOP_INT 528 -#define _POP_TOP_LOAD_CONST_INLINE 529 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 530 -#define _POP_TOP_NOP 531 -#define _POP_TOP_UNICODE 532 -#define _POP_TWO 533 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 534 +#define _POP_TOP_FLOAT 528 +#define _POP_TOP_INT 529 +#define _POP_TOP_LOAD_CONST_INLINE 530 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 531 +#define _POP_TOP_NOP 532 +#define _POP_TOP_UNICODE 533 +#define _POP_TWO 534 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 535 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 535 +#define _PUSH_FRAME 536 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 536 -#define _PY_FRAME_EX 537 -#define _PY_FRAME_GENERAL 538 -#define _PY_FRAME_KW 539 -#define _QUICKEN_RESUME 540 -#define _RECORD_4OS 541 -#define _RECORD_BOUND_METHOD 542 -#define _RECORD_CALLABLE 543 -#define _RECORD_CALLER_CODE 544 -#define _RECORD_NOS 545 -#define _RECORD_TOS 546 -#define _RECORD_TOS_TYPE 547 -#define _REPLACE_WITH_TRUE 548 +#define _PUSH_NULL_CONDITIONAL 537 +#define _PY_FRAME_EX 538 +#define _PY_FRAME_GENERAL 539 +#define _PY_FRAME_KW 540 +#define _QUICKEN_RESUME 541 +#define _RECORD_4OS 542 +#define _RECORD_BOUND_METHOD 543 +#define _RECORD_CALLABLE 544 +#define _RECORD_CODE 545 +#define _RECORD_NOS 546 +#define _RECORD_NOS_GEN_FUNC 547 +#define _RECORD_TOS 548 +#define _RECORD_TOS_TYPE 549 +#define _REPLACE_WITH_TRUE 550 #define _RESUME_CHECK RESUME_CHECK -#define _RETURN_GENERATOR 549 -#define _RETURN_VALUE 550 +#define _RETURN_GENERATOR RETURN_GENERATOR +#define _RETURN_VALUE RETURN_VALUE #define _SAVE_RETURN_OFFSET 551 #define _SEND 552 #define _SEND_GEN_FRAME 553 @@ -385,867 +387,871 @@ extern "C" { #define _UNPACK_SEQUENCE_TUPLE 587 #define _UNPACK_SEQUENCE_TWO_TUPLE 588 #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define _YIELD_VALUE 589 -#define MAX_UOP_ID 589 -#define _BINARY_OP_r23 590 -#define _BINARY_OP_ADD_FLOAT_r03 591 -#define _BINARY_OP_ADD_FLOAT_r13 592 -#define _BINARY_OP_ADD_FLOAT_r23 593 -#define _BINARY_OP_ADD_INT_r03 594 -#define _BINARY_OP_ADD_INT_r13 595 -#define _BINARY_OP_ADD_INT_r23 596 -#define _BINARY_OP_ADD_UNICODE_r03 597 -#define _BINARY_OP_ADD_UNICODE_r13 598 -#define _BINARY_OP_ADD_UNICODE_r23 599 -#define _BINARY_OP_EXTEND_r23 600 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 601 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 602 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 603 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 604 -#define _BINARY_OP_MULTIPLY_INT_r03 605 -#define _BINARY_OP_MULTIPLY_INT_r13 606 -#define _BINARY_OP_MULTIPLY_INT_r23 607 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 608 -#define _BINARY_OP_SUBSCR_DICT_r23 609 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 610 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 611 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 612 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 613 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 614 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 615 -#define _BINARY_OP_SUBSCR_STR_INT_r23 616 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 617 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 618 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 619 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 620 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 621 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 622 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 623 -#define _BINARY_OP_SUBTRACT_INT_r03 624 -#define _BINARY_OP_SUBTRACT_INT_r13 625 -#define _BINARY_OP_SUBTRACT_INT_r23 626 -#define _BINARY_SLICE_r31 627 -#define _BUILD_INTERPOLATION_r01 628 -#define _BUILD_LIST_r01 629 -#define _BUILD_MAP_r01 630 -#define _BUILD_SET_r01 631 -#define _BUILD_SLICE_r01 632 -#define _BUILD_STRING_r01 633 -#define _BUILD_TEMPLATE_r21 634 -#define _BUILD_TUPLE_r01 635 -#define _CALL_BUILTIN_CLASS_r01 636 -#define _CALL_BUILTIN_FAST_r01 637 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 638 -#define _CALL_BUILTIN_O_r03 639 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 640 -#define _CALL_INTRINSIC_1_r11 641 -#define _CALL_INTRINSIC_2_r21 642 -#define _CALL_ISINSTANCE_r31 643 -#define _CALL_KW_NON_PY_r11 644 -#define _CALL_LEN_r33 645 -#define _CALL_LIST_APPEND_r03 646 -#define _CALL_LIST_APPEND_r13 647 -#define _CALL_LIST_APPEND_r23 648 -#define _CALL_LIST_APPEND_r33 649 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 650 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 651 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 652 -#define _CALL_METHOD_DESCRIPTOR_O_r03 653 -#define _CALL_NON_PY_GENERAL_r01 654 -#define _CALL_STR_1_r32 655 -#define _CALL_TUPLE_1_r32 656 -#define _CALL_TYPE_1_r02 657 -#define _CALL_TYPE_1_r12 658 -#define _CALL_TYPE_1_r22 659 -#define _CALL_TYPE_1_r32 660 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 661 -#define _CHECK_ATTR_CLASS_r01 662 -#define _CHECK_ATTR_CLASS_r11 663 -#define _CHECK_ATTR_CLASS_r22 664 -#define _CHECK_ATTR_CLASS_r33 665 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 666 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 667 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 668 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 669 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 670 -#define _CHECK_EG_MATCH_r22 671 -#define _CHECK_EXC_MATCH_r22 672 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 673 -#define _CHECK_FUNCTION_VERSION_r00 674 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 675 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 676 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 677 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 678 -#define _CHECK_FUNCTION_VERSION_KW_r11 679 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 680 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 681 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 682 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 683 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 684 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 685 -#define _CHECK_IS_PY_CALLABLE_EX_r03 686 -#define _CHECK_IS_PY_CALLABLE_EX_r13 687 -#define _CHECK_IS_PY_CALLABLE_EX_r23 688 -#define _CHECK_IS_PY_CALLABLE_EX_r33 689 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 690 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 691 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 692 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 693 -#define _CHECK_METHOD_VERSION_r00 694 -#define _CHECK_METHOD_VERSION_KW_r11 695 -#define _CHECK_PEP_523_r00 696 -#define _CHECK_PEP_523_r11 697 -#define _CHECK_PEP_523_r22 698 -#define _CHECK_PEP_523_r33 699 -#define _CHECK_PERIODIC_r00 700 -#define _CHECK_PERIODIC_AT_END_r00 701 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 702 -#define _CHECK_RECURSION_REMAINING_r00 703 -#define _CHECK_RECURSION_REMAINING_r11 704 -#define _CHECK_RECURSION_REMAINING_r22 705 -#define _CHECK_RECURSION_REMAINING_r33 706 -#define _CHECK_STACK_SPACE_r00 707 -#define _CHECK_STACK_SPACE_OPERAND_r00 708 -#define _CHECK_STACK_SPACE_OPERAND_r11 709 -#define _CHECK_STACK_SPACE_OPERAND_r22 710 -#define _CHECK_STACK_SPACE_OPERAND_r33 711 -#define _CHECK_VALIDITY_r00 712 -#define _CHECK_VALIDITY_r11 713 -#define _CHECK_VALIDITY_r22 714 -#define _CHECK_VALIDITY_r33 715 -#define _COLD_DYNAMIC_EXIT_r00 716 -#define _COLD_EXIT_r00 717 -#define _COMPARE_OP_r21 718 -#define _COMPARE_OP_FLOAT_r03 719 -#define _COMPARE_OP_FLOAT_r13 720 -#define _COMPARE_OP_FLOAT_r23 721 -#define _COMPARE_OP_INT_r23 722 -#define _COMPARE_OP_STR_r23 723 -#define _CONTAINS_OP_r23 724 -#define _CONTAINS_OP_DICT_r23 725 -#define _CONTAINS_OP_SET_r23 726 -#define _CONVERT_VALUE_r11 727 -#define _COPY_r01 728 -#define _COPY_1_r02 729 -#define _COPY_1_r12 730 -#define _COPY_1_r23 731 -#define _COPY_2_r03 732 -#define _COPY_2_r13 733 -#define _COPY_2_r23 734 -#define _COPY_3_r03 735 -#define _COPY_3_r13 736 -#define _COPY_3_r23 737 -#define _COPY_3_r33 738 -#define _COPY_FREE_VARS_r00 739 -#define _COPY_FREE_VARS_r11 740 -#define _COPY_FREE_VARS_r22 741 -#define _COPY_FREE_VARS_r33 742 -#define _CREATE_INIT_FRAME_r01 743 -#define _DELETE_ATTR_r10 744 -#define _DELETE_DEREF_r00 745 -#define _DELETE_FAST_r00 746 -#define _DELETE_GLOBAL_r00 747 -#define _DELETE_NAME_r00 748 -#define _DELETE_SUBSCR_r20 749 -#define _DEOPT_r00 750 -#define _DEOPT_r10 751 -#define _DEOPT_r20 752 -#define _DEOPT_r30 753 -#define _DICT_MERGE_r10 754 -#define _DICT_UPDATE_r10 755 -#define _DO_CALL_r01 756 -#define _DO_CALL_FUNCTION_EX_r31 757 -#define _DO_CALL_KW_r11 758 -#define _DYNAMIC_EXIT_r00 759 -#define _DYNAMIC_EXIT_r10 760 -#define _DYNAMIC_EXIT_r20 761 -#define _DYNAMIC_EXIT_r30 762 -#define _END_FOR_r10 763 -#define _END_SEND_r21 764 -#define _ERROR_POP_N_r00 765 -#define _EXIT_INIT_CHECK_r10 766 -#define _EXIT_TRACE_r00 767 -#define _EXIT_TRACE_r10 768 -#define _EXIT_TRACE_r20 769 -#define _EXIT_TRACE_r30 770 -#define _EXPAND_METHOD_r00 771 -#define _EXPAND_METHOD_KW_r11 772 -#define _FATAL_ERROR_r00 773 -#define _FATAL_ERROR_r11 774 -#define _FATAL_ERROR_r22 775 -#define _FATAL_ERROR_r33 776 -#define _FORMAT_SIMPLE_r11 777 -#define _FORMAT_WITH_SPEC_r21 778 -#define _FOR_ITER_r23 779 -#define _FOR_ITER_GEN_FRAME_r03 780 -#define _FOR_ITER_GEN_FRAME_r13 781 -#define _FOR_ITER_GEN_FRAME_r23 782 -#define _FOR_ITER_TIER_TWO_r23 783 -#define _GET_AITER_r11 784 -#define _GET_ANEXT_r12 785 -#define _GET_AWAITABLE_r11 786 -#define _GET_ITER_r12 787 -#define _GET_LEN_r12 788 -#define _GET_YIELD_FROM_ITER_r11 789 -#define _GUARD_BINARY_OP_EXTEND_r22 790 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 791 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 792 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 793 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 794 -#define _GUARD_BIT_IS_SET_POP_r00 795 -#define _GUARD_BIT_IS_SET_POP_r10 796 -#define _GUARD_BIT_IS_SET_POP_r21 797 -#define _GUARD_BIT_IS_SET_POP_r32 798 -#define _GUARD_BIT_IS_SET_POP_4_r00 799 -#define _GUARD_BIT_IS_SET_POP_4_r10 800 -#define _GUARD_BIT_IS_SET_POP_4_r21 801 -#define _GUARD_BIT_IS_SET_POP_4_r32 802 -#define _GUARD_BIT_IS_SET_POP_5_r00 803 -#define _GUARD_BIT_IS_SET_POP_5_r10 804 -#define _GUARD_BIT_IS_SET_POP_5_r21 805 -#define _GUARD_BIT_IS_SET_POP_5_r32 806 -#define _GUARD_BIT_IS_SET_POP_6_r00 807 -#define _GUARD_BIT_IS_SET_POP_6_r10 808 -#define _GUARD_BIT_IS_SET_POP_6_r21 809 -#define _GUARD_BIT_IS_SET_POP_6_r32 810 -#define _GUARD_BIT_IS_SET_POP_7_r00 811 -#define _GUARD_BIT_IS_SET_POP_7_r10 812 -#define _GUARD_BIT_IS_SET_POP_7_r21 813 -#define _GUARD_BIT_IS_SET_POP_7_r32 814 -#define _GUARD_BIT_IS_UNSET_POP_r00 815 -#define _GUARD_BIT_IS_UNSET_POP_r10 816 -#define _GUARD_BIT_IS_UNSET_POP_r21 817 -#define _GUARD_BIT_IS_UNSET_POP_r32 818 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 819 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 820 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 821 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 822 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 823 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 824 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 825 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 826 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 827 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 828 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 829 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 830 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 831 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 832 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 833 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 834 -#define _GUARD_CALLABLE_ISINSTANCE_r03 835 -#define _GUARD_CALLABLE_ISINSTANCE_r13 836 -#define _GUARD_CALLABLE_ISINSTANCE_r23 837 -#define _GUARD_CALLABLE_ISINSTANCE_r33 838 -#define _GUARD_CALLABLE_LEN_r03 839 -#define _GUARD_CALLABLE_LEN_r13 840 -#define _GUARD_CALLABLE_LEN_r23 841 -#define _GUARD_CALLABLE_LEN_r33 842 -#define _GUARD_CALLABLE_LIST_APPEND_r03 843 -#define _GUARD_CALLABLE_LIST_APPEND_r13 844 -#define _GUARD_CALLABLE_LIST_APPEND_r23 845 -#define _GUARD_CALLABLE_LIST_APPEND_r33 846 -#define _GUARD_CALLABLE_STR_1_r03 847 -#define _GUARD_CALLABLE_STR_1_r13 848 -#define _GUARD_CALLABLE_STR_1_r23 849 -#define _GUARD_CALLABLE_STR_1_r33 850 -#define _GUARD_CALLABLE_TUPLE_1_r03 851 -#define _GUARD_CALLABLE_TUPLE_1_r13 852 -#define _GUARD_CALLABLE_TUPLE_1_r23 853 -#define _GUARD_CALLABLE_TUPLE_1_r33 854 -#define _GUARD_CALLABLE_TYPE_1_r03 855 -#define _GUARD_CALLABLE_TYPE_1_r13 856 -#define _GUARD_CALLABLE_TYPE_1_r23 857 -#define _GUARD_CALLABLE_TYPE_1_r33 858 -#define _GUARD_DORV_NO_DICT_r01 859 -#define _GUARD_DORV_NO_DICT_r11 860 -#define _GUARD_DORV_NO_DICT_r22 861 -#define _GUARD_DORV_NO_DICT_r33 862 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 863 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 864 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 865 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 866 -#define _GUARD_GLOBALS_VERSION_r00 867 -#define _GUARD_GLOBALS_VERSION_r11 868 -#define _GUARD_GLOBALS_VERSION_r22 869 -#define _GUARD_GLOBALS_VERSION_r33 870 -#define _GUARD_IP_RETURN_GENERATOR_r00 871 -#define _GUARD_IP_RETURN_GENERATOR_r11 872 -#define _GUARD_IP_RETURN_GENERATOR_r22 873 -#define _GUARD_IP_RETURN_GENERATOR_r33 874 -#define _GUARD_IP_RETURN_VALUE_r00 875 -#define _GUARD_IP_RETURN_VALUE_r11 876 -#define _GUARD_IP_RETURN_VALUE_r22 877 -#define _GUARD_IP_RETURN_VALUE_r33 878 -#define _GUARD_IP_YIELD_VALUE_r00 879 -#define _GUARD_IP_YIELD_VALUE_r11 880 -#define _GUARD_IP_YIELD_VALUE_r22 881 -#define _GUARD_IP_YIELD_VALUE_r33 882 -#define _GUARD_IP__PUSH_FRAME_r00 883 -#define _GUARD_IP__PUSH_FRAME_r11 884 -#define _GUARD_IP__PUSH_FRAME_r22 885 -#define _GUARD_IP__PUSH_FRAME_r33 886 -#define _GUARD_IS_FALSE_POP_r00 887 -#define _GUARD_IS_FALSE_POP_r10 888 -#define _GUARD_IS_FALSE_POP_r21 889 -#define _GUARD_IS_FALSE_POP_r32 890 -#define _GUARD_IS_NONE_POP_r00 891 -#define _GUARD_IS_NONE_POP_r10 892 -#define _GUARD_IS_NONE_POP_r21 893 -#define _GUARD_IS_NONE_POP_r32 894 -#define _GUARD_IS_NOT_NONE_POP_r10 895 -#define _GUARD_IS_TRUE_POP_r00 896 -#define _GUARD_IS_TRUE_POP_r10 897 -#define _GUARD_IS_TRUE_POP_r21 898 -#define _GUARD_IS_TRUE_POP_r32 899 -#define _GUARD_KEYS_VERSION_r01 900 -#define _GUARD_KEYS_VERSION_r11 901 -#define _GUARD_KEYS_VERSION_r22 902 -#define _GUARD_KEYS_VERSION_r33 903 -#define _GUARD_NOS_COMPACT_ASCII_r02 904 -#define _GUARD_NOS_COMPACT_ASCII_r12 905 -#define _GUARD_NOS_COMPACT_ASCII_r22 906 -#define _GUARD_NOS_COMPACT_ASCII_r33 907 -#define _GUARD_NOS_DICT_r02 908 -#define _GUARD_NOS_DICT_r12 909 -#define _GUARD_NOS_DICT_r22 910 -#define _GUARD_NOS_DICT_r33 911 -#define _GUARD_NOS_FLOAT_r02 912 -#define _GUARD_NOS_FLOAT_r12 913 -#define _GUARD_NOS_FLOAT_r22 914 -#define _GUARD_NOS_FLOAT_r33 915 -#define _GUARD_NOS_INT_r02 916 -#define _GUARD_NOS_INT_r12 917 -#define _GUARD_NOS_INT_r22 918 -#define _GUARD_NOS_INT_r33 919 -#define _GUARD_NOS_LIST_r02 920 -#define _GUARD_NOS_LIST_r12 921 -#define _GUARD_NOS_LIST_r22 922 -#define _GUARD_NOS_LIST_r33 923 -#define _GUARD_NOS_NOT_NULL_r02 924 -#define _GUARD_NOS_NOT_NULL_r12 925 -#define _GUARD_NOS_NOT_NULL_r22 926 -#define _GUARD_NOS_NOT_NULL_r33 927 -#define _GUARD_NOS_NULL_r02 928 -#define _GUARD_NOS_NULL_r12 929 -#define _GUARD_NOS_NULL_r22 930 -#define _GUARD_NOS_NULL_r33 931 -#define _GUARD_NOS_OVERFLOWED_r02 932 -#define _GUARD_NOS_OVERFLOWED_r12 933 -#define _GUARD_NOS_OVERFLOWED_r22 934 -#define _GUARD_NOS_OVERFLOWED_r33 935 -#define _GUARD_NOS_TUPLE_r02 936 -#define _GUARD_NOS_TUPLE_r12 937 -#define _GUARD_NOS_TUPLE_r22 938 -#define _GUARD_NOS_TUPLE_r33 939 -#define _GUARD_NOS_UNICODE_r02 940 -#define _GUARD_NOS_UNICODE_r12 941 -#define _GUARD_NOS_UNICODE_r22 942 -#define _GUARD_NOS_UNICODE_r33 943 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 944 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 945 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 946 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 947 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 948 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 949 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 950 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 951 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 952 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 953 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 954 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 955 -#define _GUARD_THIRD_NULL_r03 956 -#define _GUARD_THIRD_NULL_r13 957 -#define _GUARD_THIRD_NULL_r23 958 -#define _GUARD_THIRD_NULL_r33 959 -#define _GUARD_TOS_ANY_SET_r01 960 -#define _GUARD_TOS_ANY_SET_r11 961 -#define _GUARD_TOS_ANY_SET_r22 962 -#define _GUARD_TOS_ANY_SET_r33 963 -#define _GUARD_TOS_DICT_r01 964 -#define _GUARD_TOS_DICT_r11 965 -#define _GUARD_TOS_DICT_r22 966 -#define _GUARD_TOS_DICT_r33 967 -#define _GUARD_TOS_FLOAT_r01 968 -#define _GUARD_TOS_FLOAT_r11 969 -#define _GUARD_TOS_FLOAT_r22 970 -#define _GUARD_TOS_FLOAT_r33 971 -#define _GUARD_TOS_INT_r01 972 -#define _GUARD_TOS_INT_r11 973 -#define _GUARD_TOS_INT_r22 974 -#define _GUARD_TOS_INT_r33 975 -#define _GUARD_TOS_LIST_r01 976 -#define _GUARD_TOS_LIST_r11 977 -#define _GUARD_TOS_LIST_r22 978 -#define _GUARD_TOS_LIST_r33 979 -#define _GUARD_TOS_OVERFLOWED_r01 980 -#define _GUARD_TOS_OVERFLOWED_r11 981 -#define _GUARD_TOS_OVERFLOWED_r22 982 -#define _GUARD_TOS_OVERFLOWED_r33 983 -#define _GUARD_TOS_SLICE_r01 984 -#define _GUARD_TOS_SLICE_r11 985 -#define _GUARD_TOS_SLICE_r22 986 -#define _GUARD_TOS_SLICE_r33 987 -#define _GUARD_TOS_TUPLE_r01 988 -#define _GUARD_TOS_TUPLE_r11 989 -#define _GUARD_TOS_TUPLE_r22 990 -#define _GUARD_TOS_TUPLE_r33 991 -#define _GUARD_TOS_UNICODE_r01 992 -#define _GUARD_TOS_UNICODE_r11 993 -#define _GUARD_TOS_UNICODE_r22 994 -#define _GUARD_TOS_UNICODE_r33 995 -#define _GUARD_TYPE_VERSION_r01 996 -#define _GUARD_TYPE_VERSION_r11 997 -#define _GUARD_TYPE_VERSION_r22 998 -#define _GUARD_TYPE_VERSION_r33 999 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 1000 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 1001 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 1002 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 1003 -#define _HANDLE_PENDING_AND_DEOPT_r00 1004 -#define _HANDLE_PENDING_AND_DEOPT_r10 1005 -#define _HANDLE_PENDING_AND_DEOPT_r20 1006 -#define _HANDLE_PENDING_AND_DEOPT_r30 1007 -#define _IMPORT_FROM_r12 1008 -#define _IMPORT_NAME_r21 1009 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1010 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1011 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1012 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1013 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1014 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1015 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1016 -#define _INSERT_1_LOAD_CONST_INLINE_r02 1017 -#define _INSERT_1_LOAD_CONST_INLINE_r12 1018 -#define _INSERT_1_LOAD_CONST_INLINE_r23 1019 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1020 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1021 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1022 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1023 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1024 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1025 -#define _INSERT_NULL_r10 1026 -#define _INSTRUMENTED_FOR_ITER_r23 1027 -#define _INSTRUMENTED_INSTRUCTION_r00 1028 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1029 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1030 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1031 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1032 -#define _INSTRUMENTED_LINE_r00 1033 -#define _INSTRUMENTED_NOT_TAKEN_r00 1034 -#define _INSTRUMENTED_NOT_TAKEN_r11 1035 -#define _INSTRUMENTED_NOT_TAKEN_r22 1036 -#define _INSTRUMENTED_NOT_TAKEN_r33 1037 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1038 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1039 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1040 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1041 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1042 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1043 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1044 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1045 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1046 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1047 -#define _IS_NONE_r11 1048 -#define _IS_OP_r03 1049 -#define _IS_OP_r13 1050 -#define _IS_OP_r23 1051 -#define _ITER_CHECK_LIST_r02 1052 -#define _ITER_CHECK_LIST_r12 1053 -#define _ITER_CHECK_LIST_r22 1054 -#define _ITER_CHECK_LIST_r33 1055 -#define _ITER_CHECK_RANGE_r02 1056 -#define _ITER_CHECK_RANGE_r12 1057 -#define _ITER_CHECK_RANGE_r22 1058 -#define _ITER_CHECK_RANGE_r33 1059 -#define _ITER_CHECK_TUPLE_r02 1060 -#define _ITER_CHECK_TUPLE_r12 1061 -#define _ITER_CHECK_TUPLE_r22 1062 -#define _ITER_CHECK_TUPLE_r33 1063 -#define _ITER_JUMP_LIST_r02 1064 -#define _ITER_JUMP_LIST_r12 1065 -#define _ITER_JUMP_LIST_r22 1066 -#define _ITER_JUMP_LIST_r33 1067 -#define _ITER_JUMP_RANGE_r02 1068 -#define _ITER_JUMP_RANGE_r12 1069 -#define _ITER_JUMP_RANGE_r22 1070 -#define _ITER_JUMP_RANGE_r33 1071 -#define _ITER_JUMP_TUPLE_r02 1072 -#define _ITER_JUMP_TUPLE_r12 1073 -#define _ITER_JUMP_TUPLE_r22 1074 -#define _ITER_JUMP_TUPLE_r33 1075 -#define _ITER_NEXT_LIST_r23 1076 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1077 -#define _ITER_NEXT_RANGE_r03 1078 -#define _ITER_NEXT_RANGE_r13 1079 -#define _ITER_NEXT_RANGE_r23 1080 -#define _ITER_NEXT_TUPLE_r03 1081 -#define _ITER_NEXT_TUPLE_r13 1082 -#define _ITER_NEXT_TUPLE_r23 1083 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1084 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1085 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1086 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1087 -#define _JUMP_TO_TOP_r00 1088 -#define _LIST_APPEND_r10 1089 -#define _LIST_EXTEND_r10 1090 -#define _LOAD_ATTR_r10 1091 -#define _LOAD_ATTR_CLASS_r11 1092 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1093 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1094 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1095 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1096 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1097 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1098 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1099 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1100 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1101 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1102 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1103 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1104 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1105 -#define _LOAD_ATTR_MODULE_r12 1106 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1107 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1108 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1109 -#define _LOAD_ATTR_SLOT_r02 1110 -#define _LOAD_ATTR_SLOT_r12 1111 -#define _LOAD_ATTR_SLOT_r23 1112 -#define _LOAD_ATTR_WITH_HINT_r12 1113 -#define _LOAD_BUILD_CLASS_r01 1114 -#define _LOAD_BYTECODE_r00 1115 -#define _LOAD_COMMON_CONSTANT_r01 1116 -#define _LOAD_COMMON_CONSTANT_r12 1117 -#define _LOAD_COMMON_CONSTANT_r23 1118 -#define _LOAD_CONST_r01 1119 -#define _LOAD_CONST_r12 1120 -#define _LOAD_CONST_r23 1121 -#define _LOAD_CONST_INLINE_r01 1122 -#define _LOAD_CONST_INLINE_r12 1123 -#define _LOAD_CONST_INLINE_r23 1124 -#define _LOAD_CONST_INLINE_BORROW_r01 1125 -#define _LOAD_CONST_INLINE_BORROW_r12 1126 -#define _LOAD_CONST_INLINE_BORROW_r23 1127 -#define _LOAD_CONST_UNDER_INLINE_r02 1128 -#define _LOAD_CONST_UNDER_INLINE_r12 1129 -#define _LOAD_CONST_UNDER_INLINE_r23 1130 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1131 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1132 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1133 -#define _LOAD_DEREF_r01 1134 -#define _LOAD_FAST_r01 1135 -#define _LOAD_FAST_r12 1136 -#define _LOAD_FAST_r23 1137 -#define _LOAD_FAST_0_r01 1138 -#define _LOAD_FAST_0_r12 1139 -#define _LOAD_FAST_0_r23 1140 -#define _LOAD_FAST_1_r01 1141 -#define _LOAD_FAST_1_r12 1142 -#define _LOAD_FAST_1_r23 1143 -#define _LOAD_FAST_2_r01 1144 -#define _LOAD_FAST_2_r12 1145 -#define _LOAD_FAST_2_r23 1146 -#define _LOAD_FAST_3_r01 1147 -#define _LOAD_FAST_3_r12 1148 -#define _LOAD_FAST_3_r23 1149 -#define _LOAD_FAST_4_r01 1150 -#define _LOAD_FAST_4_r12 1151 -#define _LOAD_FAST_4_r23 1152 -#define _LOAD_FAST_5_r01 1153 -#define _LOAD_FAST_5_r12 1154 -#define _LOAD_FAST_5_r23 1155 -#define _LOAD_FAST_6_r01 1156 -#define _LOAD_FAST_6_r12 1157 -#define _LOAD_FAST_6_r23 1158 -#define _LOAD_FAST_7_r01 1159 -#define _LOAD_FAST_7_r12 1160 -#define _LOAD_FAST_7_r23 1161 -#define _LOAD_FAST_AND_CLEAR_r01 1162 -#define _LOAD_FAST_AND_CLEAR_r12 1163 -#define _LOAD_FAST_AND_CLEAR_r23 1164 -#define _LOAD_FAST_BORROW_r01 1165 -#define _LOAD_FAST_BORROW_r12 1166 -#define _LOAD_FAST_BORROW_r23 1167 -#define _LOAD_FAST_BORROW_0_r01 1168 -#define _LOAD_FAST_BORROW_0_r12 1169 -#define _LOAD_FAST_BORROW_0_r23 1170 -#define _LOAD_FAST_BORROW_1_r01 1171 -#define _LOAD_FAST_BORROW_1_r12 1172 -#define _LOAD_FAST_BORROW_1_r23 1173 -#define _LOAD_FAST_BORROW_2_r01 1174 -#define _LOAD_FAST_BORROW_2_r12 1175 -#define _LOAD_FAST_BORROW_2_r23 1176 -#define _LOAD_FAST_BORROW_3_r01 1177 -#define _LOAD_FAST_BORROW_3_r12 1178 -#define _LOAD_FAST_BORROW_3_r23 1179 -#define _LOAD_FAST_BORROW_4_r01 1180 -#define _LOAD_FAST_BORROW_4_r12 1181 -#define _LOAD_FAST_BORROW_4_r23 1182 -#define _LOAD_FAST_BORROW_5_r01 1183 -#define _LOAD_FAST_BORROW_5_r12 1184 -#define _LOAD_FAST_BORROW_5_r23 1185 -#define _LOAD_FAST_BORROW_6_r01 1186 -#define _LOAD_FAST_BORROW_6_r12 1187 -#define _LOAD_FAST_BORROW_6_r23 1188 -#define _LOAD_FAST_BORROW_7_r01 1189 -#define _LOAD_FAST_BORROW_7_r12 1190 -#define _LOAD_FAST_BORROW_7_r23 1191 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1192 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1193 -#define _LOAD_FAST_CHECK_r01 1194 -#define _LOAD_FAST_CHECK_r12 1195 -#define _LOAD_FAST_CHECK_r23 1196 -#define _LOAD_FAST_LOAD_FAST_r02 1197 -#define _LOAD_FAST_LOAD_FAST_r13 1198 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1199 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1200 -#define _LOAD_GLOBAL_r00 1201 -#define _LOAD_GLOBAL_BUILTINS_r01 1202 -#define _LOAD_GLOBAL_MODULE_r01 1203 -#define _LOAD_LOCALS_r01 1204 -#define _LOAD_LOCALS_r12 1205 -#define _LOAD_LOCALS_r23 1206 -#define _LOAD_NAME_r01 1207 -#define _LOAD_SMALL_INT_r01 1208 -#define _LOAD_SMALL_INT_r12 1209 -#define _LOAD_SMALL_INT_r23 1210 -#define _LOAD_SMALL_INT_0_r01 1211 -#define _LOAD_SMALL_INT_0_r12 1212 -#define _LOAD_SMALL_INT_0_r23 1213 -#define _LOAD_SMALL_INT_1_r01 1214 -#define _LOAD_SMALL_INT_1_r12 1215 -#define _LOAD_SMALL_INT_1_r23 1216 -#define _LOAD_SMALL_INT_2_r01 1217 -#define _LOAD_SMALL_INT_2_r12 1218 -#define _LOAD_SMALL_INT_2_r23 1219 -#define _LOAD_SMALL_INT_3_r01 1220 -#define _LOAD_SMALL_INT_3_r12 1221 -#define _LOAD_SMALL_INT_3_r23 1222 -#define _LOAD_SPECIAL_r00 1223 -#define _LOAD_SUPER_ATTR_ATTR_r31 1224 -#define _LOAD_SUPER_ATTR_METHOD_r32 1225 -#define _MAKE_CALLARGS_A_TUPLE_r33 1226 -#define _MAKE_CELL_r00 1227 -#define _MAKE_FUNCTION_r11 1228 -#define _MAKE_WARM_r00 1229 -#define _MAKE_WARM_r11 1230 -#define _MAKE_WARM_r22 1231 -#define _MAKE_WARM_r33 1232 -#define _MAP_ADD_r20 1233 -#define _MATCH_CLASS_r31 1234 -#define _MATCH_KEYS_r23 1235 -#define _MATCH_MAPPING_r02 1236 -#define _MATCH_MAPPING_r12 1237 -#define _MATCH_MAPPING_r23 1238 -#define _MATCH_SEQUENCE_r02 1239 -#define _MATCH_SEQUENCE_r12 1240 -#define _MATCH_SEQUENCE_r23 1241 -#define _MAYBE_EXPAND_METHOD_r00 1242 -#define _MAYBE_EXPAND_METHOD_KW_r11 1243 -#define _MONITOR_CALL_r00 1244 -#define _MONITOR_CALL_KW_r11 1245 -#define _MONITOR_JUMP_BACKWARD_r00 1246 -#define _MONITOR_JUMP_BACKWARD_r11 1247 -#define _MONITOR_JUMP_BACKWARD_r22 1248 -#define _MONITOR_JUMP_BACKWARD_r33 1249 -#define _MONITOR_RESUME_r00 1250 -#define _NOP_r00 1251 -#define _NOP_r11 1252 -#define _NOP_r22 1253 -#define _NOP_r33 1254 -#define _POP_CALL_r20 1255 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1256 -#define _POP_CALL_ONE_r30 1257 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1258 -#define _POP_CALL_TWO_r30 1259 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1260 -#define _POP_EXCEPT_r10 1261 -#define _POP_ITER_r20 1262 -#define _POP_JUMP_IF_FALSE_r00 1263 -#define _POP_JUMP_IF_FALSE_r10 1264 -#define _POP_JUMP_IF_FALSE_r21 1265 -#define _POP_JUMP_IF_FALSE_r32 1266 -#define _POP_JUMP_IF_TRUE_r00 1267 -#define _POP_JUMP_IF_TRUE_r10 1268 -#define _POP_JUMP_IF_TRUE_r21 1269 -#define _POP_JUMP_IF_TRUE_r32 1270 -#define _POP_TOP_r10 1271 -#define _POP_TOP_FLOAT_r00 1272 -#define _POP_TOP_FLOAT_r10 1273 -#define _POP_TOP_FLOAT_r21 1274 -#define _POP_TOP_FLOAT_r32 1275 -#define _POP_TOP_INT_r00 1276 -#define _POP_TOP_INT_r10 1277 -#define _POP_TOP_INT_r21 1278 -#define _POP_TOP_INT_r32 1279 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1280 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1281 -#define _POP_TOP_NOP_r00 1282 -#define _POP_TOP_NOP_r10 1283 -#define _POP_TOP_NOP_r21 1284 -#define _POP_TOP_NOP_r32 1285 -#define _POP_TOP_UNICODE_r00 1286 -#define _POP_TOP_UNICODE_r10 1287 -#define _POP_TOP_UNICODE_r21 1288 -#define _POP_TOP_UNICODE_r32 1289 -#define _POP_TWO_r20 1290 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1291 -#define _PUSH_EXC_INFO_r02 1292 -#define _PUSH_EXC_INFO_r12 1293 -#define _PUSH_EXC_INFO_r23 1294 -#define _PUSH_FRAME_r10 1295 -#define _PUSH_NULL_r01 1296 -#define _PUSH_NULL_r12 1297 -#define _PUSH_NULL_r23 1298 -#define _PUSH_NULL_CONDITIONAL_r00 1299 -#define _PY_FRAME_EX_r31 1300 -#define _PY_FRAME_GENERAL_r01 1301 -#define _PY_FRAME_KW_r11 1302 -#define _QUICKEN_RESUME_r00 1303 -#define _QUICKEN_RESUME_r11 1304 -#define _QUICKEN_RESUME_r22 1305 -#define _QUICKEN_RESUME_r33 1306 -#define _REPLACE_WITH_TRUE_r02 1307 -#define _REPLACE_WITH_TRUE_r12 1308 -#define _REPLACE_WITH_TRUE_r23 1309 -#define _RESUME_CHECK_r00 1310 -#define _RESUME_CHECK_r11 1311 -#define _RESUME_CHECK_r22 1312 -#define _RESUME_CHECK_r33 1313 -#define _RETURN_GENERATOR_r01 1314 -#define _RETURN_VALUE_r11 1315 -#define _SAVE_RETURN_OFFSET_r00 1316 -#define _SAVE_RETURN_OFFSET_r11 1317 -#define _SAVE_RETURN_OFFSET_r22 1318 -#define _SAVE_RETURN_OFFSET_r33 1319 -#define _SEND_r22 1320 -#define _SEND_GEN_FRAME_r22 1321 -#define _SETUP_ANNOTATIONS_r00 1322 -#define _SET_ADD_r10 1323 -#define _SET_FUNCTION_ATTRIBUTE_r01 1324 -#define _SET_FUNCTION_ATTRIBUTE_r11 1325 -#define _SET_FUNCTION_ATTRIBUTE_r21 1326 -#define _SET_FUNCTION_ATTRIBUTE_r32 1327 -#define _SET_IP_r00 1328 -#define _SET_IP_r11 1329 -#define _SET_IP_r22 1330 -#define _SET_IP_r33 1331 -#define _SET_UPDATE_r10 1332 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1333 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1334 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1335 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1336 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1337 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1338 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1339 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1340 -#define _SPILL_OR_RELOAD_r01 1341 -#define _SPILL_OR_RELOAD_r02 1342 -#define _SPILL_OR_RELOAD_r03 1343 -#define _SPILL_OR_RELOAD_r10 1344 -#define _SPILL_OR_RELOAD_r12 1345 -#define _SPILL_OR_RELOAD_r13 1346 -#define _SPILL_OR_RELOAD_r20 1347 -#define _SPILL_OR_RELOAD_r21 1348 -#define _SPILL_OR_RELOAD_r23 1349 -#define _SPILL_OR_RELOAD_r30 1350 -#define _SPILL_OR_RELOAD_r31 1351 -#define _SPILL_OR_RELOAD_r32 1352 -#define _START_EXECUTOR_r00 1353 -#define _STORE_ATTR_r20 1354 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1355 -#define _STORE_ATTR_SLOT_r21 1356 -#define _STORE_ATTR_WITH_HINT_r21 1357 -#define _STORE_DEREF_r10 1358 -#define _STORE_FAST_LOAD_FAST_r11 1359 -#define _STORE_FAST_STORE_FAST_r20 1360 -#define _STORE_GLOBAL_r10 1361 -#define _STORE_NAME_r10 1362 -#define _STORE_SLICE_r30 1363 -#define _STORE_SUBSCR_r30 1364 -#define _STORE_SUBSCR_DICT_r31 1365 -#define _STORE_SUBSCR_LIST_INT_r32 1366 -#define _SWAP_r11 1367 -#define _SWAP_2_r02 1368 -#define _SWAP_2_r12 1369 -#define _SWAP_2_r22 1370 -#define _SWAP_2_r33 1371 -#define _SWAP_3_r03 1372 -#define _SWAP_3_r13 1373 -#define _SWAP_3_r23 1374 -#define _SWAP_3_r33 1375 -#define _SWAP_FAST_r01 1376 -#define _SWAP_FAST_r11 1377 -#define _SWAP_FAST_r22 1378 -#define _SWAP_FAST_r33 1379 -#define _SWAP_FAST_0_r01 1380 -#define _SWAP_FAST_0_r11 1381 -#define _SWAP_FAST_0_r22 1382 -#define _SWAP_FAST_0_r33 1383 -#define _SWAP_FAST_1_r01 1384 -#define _SWAP_FAST_1_r11 1385 -#define _SWAP_FAST_1_r22 1386 -#define _SWAP_FAST_1_r33 1387 -#define _SWAP_FAST_2_r01 1388 -#define _SWAP_FAST_2_r11 1389 -#define _SWAP_FAST_2_r22 1390 -#define _SWAP_FAST_2_r33 1391 -#define _SWAP_FAST_3_r01 1392 -#define _SWAP_FAST_3_r11 1393 -#define _SWAP_FAST_3_r22 1394 -#define _SWAP_FAST_3_r33 1395 -#define _SWAP_FAST_4_r01 1396 -#define _SWAP_FAST_4_r11 1397 -#define _SWAP_FAST_4_r22 1398 -#define _SWAP_FAST_4_r33 1399 -#define _SWAP_FAST_5_r01 1400 -#define _SWAP_FAST_5_r11 1401 -#define _SWAP_FAST_5_r22 1402 -#define _SWAP_FAST_5_r33 1403 -#define _SWAP_FAST_6_r01 1404 -#define _SWAP_FAST_6_r11 1405 -#define _SWAP_FAST_6_r22 1406 -#define _SWAP_FAST_6_r33 1407 -#define _SWAP_FAST_7_r01 1408 -#define _SWAP_FAST_7_r11 1409 -#define _SWAP_FAST_7_r22 1410 -#define _SWAP_FAST_7_r33 1411 -#define _TIER2_RESUME_CHECK_r00 1412 -#define _TIER2_RESUME_CHECK_r11 1413 -#define _TIER2_RESUME_CHECK_r22 1414 -#define _TIER2_RESUME_CHECK_r33 1415 -#define _TO_BOOL_r11 1416 -#define _TO_BOOL_BOOL_r01 1417 -#define _TO_BOOL_BOOL_r11 1418 -#define _TO_BOOL_BOOL_r22 1419 -#define _TO_BOOL_BOOL_r33 1420 -#define _TO_BOOL_INT_r02 1421 -#define _TO_BOOL_INT_r12 1422 -#define _TO_BOOL_INT_r23 1423 -#define _TO_BOOL_LIST_r02 1424 -#define _TO_BOOL_LIST_r12 1425 -#define _TO_BOOL_LIST_r23 1426 -#define _TO_BOOL_NONE_r01 1427 -#define _TO_BOOL_NONE_r11 1428 -#define _TO_BOOL_NONE_r22 1429 -#define _TO_BOOL_NONE_r33 1430 -#define _TO_BOOL_STR_r02 1431 -#define _TO_BOOL_STR_r12 1432 -#define _TO_BOOL_STR_r23 1433 -#define _TRACE_RECORD_r00 1434 -#define _UNARY_INVERT_r12 1435 -#define _UNARY_NEGATIVE_r12 1436 -#define _UNARY_NOT_r01 1437 -#define _UNARY_NOT_r11 1438 -#define _UNARY_NOT_r22 1439 -#define _UNARY_NOT_r33 1440 -#define _UNPACK_EX_r10 1441 -#define _UNPACK_SEQUENCE_r10 1442 -#define _UNPACK_SEQUENCE_LIST_r10 1443 -#define _UNPACK_SEQUENCE_TUPLE_r10 1444 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1445 -#define _WITH_EXCEPT_START_r33 1446 -#define _YIELD_VALUE_r11 1447 -#define MAX_UOP_REGS_ID 1447 +#define _YIELD_VALUE YIELD_VALUE +#define MAX_UOP_ID 588 +#define _BINARY_OP_r23 589 +#define _BINARY_OP_ADD_FLOAT_r03 590 +#define _BINARY_OP_ADD_FLOAT_r13 591 +#define _BINARY_OP_ADD_FLOAT_r23 592 +#define _BINARY_OP_ADD_INT_r03 593 +#define _BINARY_OP_ADD_INT_r13 594 +#define _BINARY_OP_ADD_INT_r23 595 +#define _BINARY_OP_ADD_UNICODE_r03 596 +#define _BINARY_OP_ADD_UNICODE_r13 597 +#define _BINARY_OP_ADD_UNICODE_r23 598 +#define _BINARY_OP_EXTEND_r23 599 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 600 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 601 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 602 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 603 +#define _BINARY_OP_MULTIPLY_INT_r03 604 +#define _BINARY_OP_MULTIPLY_INT_r13 605 +#define _BINARY_OP_MULTIPLY_INT_r23 606 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 607 +#define _BINARY_OP_SUBSCR_DICT_r23 608 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 609 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 610 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 611 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 612 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 613 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 614 +#define _BINARY_OP_SUBSCR_STR_INT_r23 615 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 616 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 617 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 618 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 619 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 620 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 621 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 622 +#define _BINARY_OP_SUBTRACT_INT_r03 623 +#define _BINARY_OP_SUBTRACT_INT_r13 624 +#define _BINARY_OP_SUBTRACT_INT_r23 625 +#define _BINARY_SLICE_r31 626 +#define _BUILD_INTERPOLATION_r01 627 +#define _BUILD_LIST_r01 628 +#define _BUILD_MAP_r01 629 +#define _BUILD_SET_r01 630 +#define _BUILD_SLICE_r01 631 +#define _BUILD_STRING_r01 632 +#define _BUILD_TEMPLATE_r21 633 +#define _BUILD_TUPLE_r01 634 +#define _CALL_BUILTIN_CLASS_r01 635 +#define _CALL_BUILTIN_FAST_r01 636 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 637 +#define _CALL_BUILTIN_O_r03 638 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 639 +#define _CALL_INTRINSIC_1_r11 640 +#define _CALL_INTRINSIC_2_r21 641 +#define _CALL_ISINSTANCE_r31 642 +#define _CALL_KW_NON_PY_r11 643 +#define _CALL_LEN_r33 644 +#define _CALL_LIST_APPEND_r03 645 +#define _CALL_LIST_APPEND_r13 646 +#define _CALL_LIST_APPEND_r23 647 +#define _CALL_LIST_APPEND_r33 648 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 649 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 650 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 651 +#define _CALL_METHOD_DESCRIPTOR_O_r03 652 +#define _CALL_NON_PY_GENERAL_r01 653 +#define _CALL_STR_1_r32 654 +#define _CALL_TUPLE_1_r32 655 +#define _CALL_TYPE_1_r02 656 +#define _CALL_TYPE_1_r12 657 +#define _CALL_TYPE_1_r22 658 +#define _CALL_TYPE_1_r32 659 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 660 +#define _CHECK_ATTR_CLASS_r01 661 +#define _CHECK_ATTR_CLASS_r11 662 +#define _CHECK_ATTR_CLASS_r22 663 +#define _CHECK_ATTR_CLASS_r33 664 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 665 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 666 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 667 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 668 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 669 +#define _CHECK_EG_MATCH_r22 670 +#define _CHECK_EXC_MATCH_r22 671 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 672 +#define _CHECK_FUNCTION_VERSION_r00 673 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 674 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 675 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 676 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 677 +#define _CHECK_FUNCTION_VERSION_KW_r11 678 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 679 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 680 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 681 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 682 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 683 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 684 +#define _CHECK_IS_PY_CALLABLE_EX_r03 685 +#define _CHECK_IS_PY_CALLABLE_EX_r13 686 +#define _CHECK_IS_PY_CALLABLE_EX_r23 687 +#define _CHECK_IS_PY_CALLABLE_EX_r33 688 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 689 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 690 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 691 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 692 +#define _CHECK_METHOD_VERSION_r00 693 +#define _CHECK_METHOD_VERSION_KW_r11 694 +#define _CHECK_PEP_523_r00 695 +#define _CHECK_PEP_523_r11 696 +#define _CHECK_PEP_523_r22 697 +#define _CHECK_PEP_523_r33 698 +#define _CHECK_PERIODIC_r00 699 +#define _CHECK_PERIODIC_AT_END_r00 700 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 701 +#define _CHECK_RECURSION_REMAINING_r00 702 +#define _CHECK_RECURSION_REMAINING_r11 703 +#define _CHECK_RECURSION_REMAINING_r22 704 +#define _CHECK_RECURSION_REMAINING_r33 705 +#define _CHECK_STACK_SPACE_r00 706 +#define _CHECK_STACK_SPACE_OPERAND_r00 707 +#define _CHECK_STACK_SPACE_OPERAND_r11 708 +#define _CHECK_STACK_SPACE_OPERAND_r22 709 +#define _CHECK_STACK_SPACE_OPERAND_r33 710 +#define _CHECK_VALIDITY_r00 711 +#define _CHECK_VALIDITY_r11 712 +#define _CHECK_VALIDITY_r22 713 +#define _CHECK_VALIDITY_r33 714 +#define _COLD_DYNAMIC_EXIT_r00 715 +#define _COLD_EXIT_r00 716 +#define _COMPARE_OP_r21 717 +#define _COMPARE_OP_FLOAT_r03 718 +#define _COMPARE_OP_FLOAT_r13 719 +#define _COMPARE_OP_FLOAT_r23 720 +#define _COMPARE_OP_INT_r23 721 +#define _COMPARE_OP_STR_r23 722 +#define _CONTAINS_OP_r23 723 +#define _CONTAINS_OP_DICT_r23 724 +#define _CONTAINS_OP_SET_r23 725 +#define _CONVERT_VALUE_r11 726 +#define _COPY_r01 727 +#define _COPY_1_r02 728 +#define _COPY_1_r12 729 +#define _COPY_1_r23 730 +#define _COPY_2_r03 731 +#define _COPY_2_r13 732 +#define _COPY_2_r23 733 +#define _COPY_3_r03 734 +#define _COPY_3_r13 735 +#define _COPY_3_r23 736 +#define _COPY_3_r33 737 +#define _COPY_FREE_VARS_r00 738 +#define _COPY_FREE_VARS_r11 739 +#define _COPY_FREE_VARS_r22 740 +#define _COPY_FREE_VARS_r33 741 +#define _CREATE_INIT_FRAME_r01 742 +#define _DELETE_ATTR_r10 743 +#define _DELETE_DEREF_r00 744 +#define _DELETE_FAST_r00 745 +#define _DELETE_GLOBAL_r00 746 +#define _DELETE_NAME_r00 747 +#define _DELETE_SUBSCR_r20 748 +#define _DEOPT_r00 749 +#define _DEOPT_r10 750 +#define _DEOPT_r20 751 +#define _DEOPT_r30 752 +#define _DICT_MERGE_r10 753 +#define _DICT_UPDATE_r10 754 +#define _DO_CALL_r01 755 +#define _DO_CALL_FUNCTION_EX_r31 756 +#define _DO_CALL_KW_r11 757 +#define _DYNAMIC_EXIT_r00 758 +#define _DYNAMIC_EXIT_r10 759 +#define _DYNAMIC_EXIT_r20 760 +#define _DYNAMIC_EXIT_r30 761 +#define _END_FOR_r10 762 +#define _END_SEND_r21 763 +#define _ERROR_POP_N_r00 764 +#define _EXIT_INIT_CHECK_r10 765 +#define _EXIT_TRACE_r00 766 +#define _EXIT_TRACE_r10 767 +#define _EXIT_TRACE_r20 768 +#define _EXIT_TRACE_r30 769 +#define _EXPAND_METHOD_r00 770 +#define _EXPAND_METHOD_KW_r11 771 +#define _FATAL_ERROR_r00 772 +#define _FATAL_ERROR_r11 773 +#define _FATAL_ERROR_r22 774 +#define _FATAL_ERROR_r33 775 +#define _FORMAT_SIMPLE_r11 776 +#define _FORMAT_WITH_SPEC_r21 777 +#define _FOR_ITER_r23 778 +#define _FOR_ITER_GEN_FRAME_r03 779 +#define _FOR_ITER_GEN_FRAME_r13 780 +#define _FOR_ITER_GEN_FRAME_r23 781 +#define _FOR_ITER_TIER_TWO_r23 782 +#define _GET_AITER_r11 783 +#define _GET_ANEXT_r12 784 +#define _GET_AWAITABLE_r11 785 +#define _GET_ITER_r12 786 +#define _GET_LEN_r12 787 +#define _GET_YIELD_FROM_ITER_r11 788 +#define _GUARD_BINARY_OP_EXTEND_r22 789 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 790 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 791 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 792 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 793 +#define _GUARD_BIT_IS_SET_POP_r00 794 +#define _GUARD_BIT_IS_SET_POP_r10 795 +#define _GUARD_BIT_IS_SET_POP_r21 796 +#define _GUARD_BIT_IS_SET_POP_r32 797 +#define _GUARD_BIT_IS_SET_POP_4_r00 798 +#define _GUARD_BIT_IS_SET_POP_4_r10 799 +#define _GUARD_BIT_IS_SET_POP_4_r21 800 +#define _GUARD_BIT_IS_SET_POP_4_r32 801 +#define _GUARD_BIT_IS_SET_POP_5_r00 802 +#define _GUARD_BIT_IS_SET_POP_5_r10 803 +#define _GUARD_BIT_IS_SET_POP_5_r21 804 +#define _GUARD_BIT_IS_SET_POP_5_r32 805 +#define _GUARD_BIT_IS_SET_POP_6_r00 806 +#define _GUARD_BIT_IS_SET_POP_6_r10 807 +#define _GUARD_BIT_IS_SET_POP_6_r21 808 +#define _GUARD_BIT_IS_SET_POP_6_r32 809 +#define _GUARD_BIT_IS_SET_POP_7_r00 810 +#define _GUARD_BIT_IS_SET_POP_7_r10 811 +#define _GUARD_BIT_IS_SET_POP_7_r21 812 +#define _GUARD_BIT_IS_SET_POP_7_r32 813 +#define _GUARD_BIT_IS_UNSET_POP_r00 814 +#define _GUARD_BIT_IS_UNSET_POP_r10 815 +#define _GUARD_BIT_IS_UNSET_POP_r21 816 +#define _GUARD_BIT_IS_UNSET_POP_r32 817 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 818 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 819 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 820 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 821 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 822 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 823 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 824 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 825 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 826 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 827 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 828 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 829 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 830 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 831 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 832 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 833 +#define _GUARD_CALLABLE_ISINSTANCE_r03 834 +#define _GUARD_CALLABLE_ISINSTANCE_r13 835 +#define _GUARD_CALLABLE_ISINSTANCE_r23 836 +#define _GUARD_CALLABLE_ISINSTANCE_r33 837 +#define _GUARD_CALLABLE_LEN_r03 838 +#define _GUARD_CALLABLE_LEN_r13 839 +#define _GUARD_CALLABLE_LEN_r23 840 +#define _GUARD_CALLABLE_LEN_r33 841 +#define _GUARD_CALLABLE_LIST_APPEND_r03 842 +#define _GUARD_CALLABLE_LIST_APPEND_r13 843 +#define _GUARD_CALLABLE_LIST_APPEND_r23 844 +#define _GUARD_CALLABLE_LIST_APPEND_r33 845 +#define _GUARD_CALLABLE_STR_1_r03 846 +#define _GUARD_CALLABLE_STR_1_r13 847 +#define _GUARD_CALLABLE_STR_1_r23 848 +#define _GUARD_CALLABLE_STR_1_r33 849 +#define _GUARD_CALLABLE_TUPLE_1_r03 850 +#define _GUARD_CALLABLE_TUPLE_1_r13 851 +#define _GUARD_CALLABLE_TUPLE_1_r23 852 +#define _GUARD_CALLABLE_TUPLE_1_r33 853 +#define _GUARD_CALLABLE_TYPE_1_r03 854 +#define _GUARD_CALLABLE_TYPE_1_r13 855 +#define _GUARD_CALLABLE_TYPE_1_r23 856 +#define _GUARD_CALLABLE_TYPE_1_r33 857 +#define _GUARD_CODE_r00 858 +#define _GUARD_CODE_r11 859 +#define _GUARD_CODE_r22 860 +#define _GUARD_CODE_r33 861 +#define _GUARD_DORV_NO_DICT_r01 862 +#define _GUARD_DORV_NO_DICT_r11 863 +#define _GUARD_DORV_NO_DICT_r22 864 +#define _GUARD_DORV_NO_DICT_r33 865 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 866 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 867 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 868 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 869 +#define _GUARD_GLOBALS_VERSION_r00 870 +#define _GUARD_GLOBALS_VERSION_r11 871 +#define _GUARD_GLOBALS_VERSION_r22 872 +#define _GUARD_GLOBALS_VERSION_r33 873 +#define _GUARD_IP_RETURN_GENERATOR_r00 874 +#define _GUARD_IP_RETURN_GENERATOR_r11 875 +#define _GUARD_IP_RETURN_GENERATOR_r22 876 +#define _GUARD_IP_RETURN_GENERATOR_r33 877 +#define _GUARD_IP_RETURN_VALUE_r00 878 +#define _GUARD_IP_RETURN_VALUE_r11 879 +#define _GUARD_IP_RETURN_VALUE_r22 880 +#define _GUARD_IP_RETURN_VALUE_r33 881 +#define _GUARD_IP_YIELD_VALUE_r00 882 +#define _GUARD_IP_YIELD_VALUE_r11 883 +#define _GUARD_IP_YIELD_VALUE_r22 884 +#define _GUARD_IP_YIELD_VALUE_r33 885 +#define _GUARD_IP__PUSH_FRAME_r00 886 +#define _GUARD_IP__PUSH_FRAME_r11 887 +#define _GUARD_IP__PUSH_FRAME_r22 888 +#define _GUARD_IP__PUSH_FRAME_r33 889 +#define _GUARD_IS_FALSE_POP_r00 890 +#define _GUARD_IS_FALSE_POP_r10 891 +#define _GUARD_IS_FALSE_POP_r21 892 +#define _GUARD_IS_FALSE_POP_r32 893 +#define _GUARD_IS_NONE_POP_r00 894 +#define _GUARD_IS_NONE_POP_r10 895 +#define _GUARD_IS_NONE_POP_r21 896 +#define _GUARD_IS_NONE_POP_r32 897 +#define _GUARD_IS_NOT_NONE_POP_r10 898 +#define _GUARD_IS_TRUE_POP_r00 899 +#define _GUARD_IS_TRUE_POP_r10 900 +#define _GUARD_IS_TRUE_POP_r21 901 +#define _GUARD_IS_TRUE_POP_r32 902 +#define _GUARD_KEYS_VERSION_r01 903 +#define _GUARD_KEYS_VERSION_r11 904 +#define _GUARD_KEYS_VERSION_r22 905 +#define _GUARD_KEYS_VERSION_r33 906 +#define _GUARD_NOS_COMPACT_ASCII_r02 907 +#define _GUARD_NOS_COMPACT_ASCII_r12 908 +#define _GUARD_NOS_COMPACT_ASCII_r22 909 +#define _GUARD_NOS_COMPACT_ASCII_r33 910 +#define _GUARD_NOS_DICT_r02 911 +#define _GUARD_NOS_DICT_r12 912 +#define _GUARD_NOS_DICT_r22 913 +#define _GUARD_NOS_DICT_r33 914 +#define _GUARD_NOS_FLOAT_r02 915 +#define _GUARD_NOS_FLOAT_r12 916 +#define _GUARD_NOS_FLOAT_r22 917 +#define _GUARD_NOS_FLOAT_r33 918 +#define _GUARD_NOS_INT_r02 919 +#define _GUARD_NOS_INT_r12 920 +#define _GUARD_NOS_INT_r22 921 +#define _GUARD_NOS_INT_r33 922 +#define _GUARD_NOS_LIST_r02 923 +#define _GUARD_NOS_LIST_r12 924 +#define _GUARD_NOS_LIST_r22 925 +#define _GUARD_NOS_LIST_r33 926 +#define _GUARD_NOS_NOT_NULL_r02 927 +#define _GUARD_NOS_NOT_NULL_r12 928 +#define _GUARD_NOS_NOT_NULL_r22 929 +#define _GUARD_NOS_NOT_NULL_r33 930 +#define _GUARD_NOS_NULL_r02 931 +#define _GUARD_NOS_NULL_r12 932 +#define _GUARD_NOS_NULL_r22 933 +#define _GUARD_NOS_NULL_r33 934 +#define _GUARD_NOS_OVERFLOWED_r02 935 +#define _GUARD_NOS_OVERFLOWED_r12 936 +#define _GUARD_NOS_OVERFLOWED_r22 937 +#define _GUARD_NOS_OVERFLOWED_r33 938 +#define _GUARD_NOS_TUPLE_r02 939 +#define _GUARD_NOS_TUPLE_r12 940 +#define _GUARD_NOS_TUPLE_r22 941 +#define _GUARD_NOS_TUPLE_r33 942 +#define _GUARD_NOS_UNICODE_r02 943 +#define _GUARD_NOS_UNICODE_r12 944 +#define _GUARD_NOS_UNICODE_r22 945 +#define _GUARD_NOS_UNICODE_r33 946 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 947 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 948 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 949 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 950 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 951 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 952 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 953 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 954 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 955 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 956 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 957 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 958 +#define _GUARD_THIRD_NULL_r03 959 +#define _GUARD_THIRD_NULL_r13 960 +#define _GUARD_THIRD_NULL_r23 961 +#define _GUARD_THIRD_NULL_r33 962 +#define _GUARD_TOS_ANY_SET_r01 963 +#define _GUARD_TOS_ANY_SET_r11 964 +#define _GUARD_TOS_ANY_SET_r22 965 +#define _GUARD_TOS_ANY_SET_r33 966 +#define _GUARD_TOS_DICT_r01 967 +#define _GUARD_TOS_DICT_r11 968 +#define _GUARD_TOS_DICT_r22 969 +#define _GUARD_TOS_DICT_r33 970 +#define _GUARD_TOS_FLOAT_r01 971 +#define _GUARD_TOS_FLOAT_r11 972 +#define _GUARD_TOS_FLOAT_r22 973 +#define _GUARD_TOS_FLOAT_r33 974 +#define _GUARD_TOS_INT_r01 975 +#define _GUARD_TOS_INT_r11 976 +#define _GUARD_TOS_INT_r22 977 +#define _GUARD_TOS_INT_r33 978 +#define _GUARD_TOS_LIST_r01 979 +#define _GUARD_TOS_LIST_r11 980 +#define _GUARD_TOS_LIST_r22 981 +#define _GUARD_TOS_LIST_r33 982 +#define _GUARD_TOS_OVERFLOWED_r01 983 +#define _GUARD_TOS_OVERFLOWED_r11 984 +#define _GUARD_TOS_OVERFLOWED_r22 985 +#define _GUARD_TOS_OVERFLOWED_r33 986 +#define _GUARD_TOS_SLICE_r01 987 +#define _GUARD_TOS_SLICE_r11 988 +#define _GUARD_TOS_SLICE_r22 989 +#define _GUARD_TOS_SLICE_r33 990 +#define _GUARD_TOS_TUPLE_r01 991 +#define _GUARD_TOS_TUPLE_r11 992 +#define _GUARD_TOS_TUPLE_r22 993 +#define _GUARD_TOS_TUPLE_r33 994 +#define _GUARD_TOS_UNICODE_r01 995 +#define _GUARD_TOS_UNICODE_r11 996 +#define _GUARD_TOS_UNICODE_r22 997 +#define _GUARD_TOS_UNICODE_r33 998 +#define _GUARD_TYPE_VERSION_r01 999 +#define _GUARD_TYPE_VERSION_r11 1000 +#define _GUARD_TYPE_VERSION_r22 1001 +#define _GUARD_TYPE_VERSION_r33 1002 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 1003 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 1004 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 1005 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 1006 +#define _HANDLE_PENDING_AND_DEOPT_r00 1007 +#define _HANDLE_PENDING_AND_DEOPT_r10 1008 +#define _HANDLE_PENDING_AND_DEOPT_r20 1009 +#define _HANDLE_PENDING_AND_DEOPT_r30 1010 +#define _IMPORT_FROM_r12 1011 +#define _IMPORT_NAME_r21 1012 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1013 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1014 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1015 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1016 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1017 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1018 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1019 +#define _INSERT_1_LOAD_CONST_INLINE_r02 1020 +#define _INSERT_1_LOAD_CONST_INLINE_r12 1021 +#define _INSERT_1_LOAD_CONST_INLINE_r23 1022 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1023 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1024 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1025 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1026 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1027 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1028 +#define _INSERT_NULL_r10 1029 +#define _INSTRUMENTED_FOR_ITER_r23 1030 +#define _INSTRUMENTED_INSTRUCTION_r00 1031 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1032 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1033 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1034 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1035 +#define _INSTRUMENTED_LINE_r00 1036 +#define _INSTRUMENTED_NOT_TAKEN_r00 1037 +#define _INSTRUMENTED_NOT_TAKEN_r11 1038 +#define _INSTRUMENTED_NOT_TAKEN_r22 1039 +#define _INSTRUMENTED_NOT_TAKEN_r33 1040 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1041 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1042 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1043 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1044 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1045 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1046 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1047 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1048 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1049 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1050 +#define _IS_NONE_r11 1051 +#define _IS_OP_r03 1052 +#define _IS_OP_r13 1053 +#define _IS_OP_r23 1054 +#define _ITER_CHECK_LIST_r02 1055 +#define _ITER_CHECK_LIST_r12 1056 +#define _ITER_CHECK_LIST_r22 1057 +#define _ITER_CHECK_LIST_r33 1058 +#define _ITER_CHECK_RANGE_r02 1059 +#define _ITER_CHECK_RANGE_r12 1060 +#define _ITER_CHECK_RANGE_r22 1061 +#define _ITER_CHECK_RANGE_r33 1062 +#define _ITER_CHECK_TUPLE_r02 1063 +#define _ITER_CHECK_TUPLE_r12 1064 +#define _ITER_CHECK_TUPLE_r22 1065 +#define _ITER_CHECK_TUPLE_r33 1066 +#define _ITER_JUMP_LIST_r02 1067 +#define _ITER_JUMP_LIST_r12 1068 +#define _ITER_JUMP_LIST_r22 1069 +#define _ITER_JUMP_LIST_r33 1070 +#define _ITER_JUMP_RANGE_r02 1071 +#define _ITER_JUMP_RANGE_r12 1072 +#define _ITER_JUMP_RANGE_r22 1073 +#define _ITER_JUMP_RANGE_r33 1074 +#define _ITER_JUMP_TUPLE_r02 1075 +#define _ITER_JUMP_TUPLE_r12 1076 +#define _ITER_JUMP_TUPLE_r22 1077 +#define _ITER_JUMP_TUPLE_r33 1078 +#define _ITER_NEXT_LIST_r23 1079 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1080 +#define _ITER_NEXT_RANGE_r03 1081 +#define _ITER_NEXT_RANGE_r13 1082 +#define _ITER_NEXT_RANGE_r23 1083 +#define _ITER_NEXT_TUPLE_r03 1084 +#define _ITER_NEXT_TUPLE_r13 1085 +#define _ITER_NEXT_TUPLE_r23 1086 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1087 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1088 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1089 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1090 +#define _JUMP_TO_TOP_r00 1091 +#define _LIST_APPEND_r10 1092 +#define _LIST_EXTEND_r10 1093 +#define _LOAD_ATTR_r10 1094 +#define _LOAD_ATTR_CLASS_r11 1095 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1096 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1097 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1098 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1099 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1100 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1101 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1102 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1103 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1104 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1105 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1106 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1107 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1108 +#define _LOAD_ATTR_MODULE_r12 1109 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1110 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1111 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1112 +#define _LOAD_ATTR_SLOT_r02 1113 +#define _LOAD_ATTR_SLOT_r12 1114 +#define _LOAD_ATTR_SLOT_r23 1115 +#define _LOAD_ATTR_WITH_HINT_r12 1116 +#define _LOAD_BUILD_CLASS_r01 1117 +#define _LOAD_BYTECODE_r00 1118 +#define _LOAD_COMMON_CONSTANT_r01 1119 +#define _LOAD_COMMON_CONSTANT_r12 1120 +#define _LOAD_COMMON_CONSTANT_r23 1121 +#define _LOAD_CONST_r01 1122 +#define _LOAD_CONST_r12 1123 +#define _LOAD_CONST_r23 1124 +#define _LOAD_CONST_INLINE_r01 1125 +#define _LOAD_CONST_INLINE_r12 1126 +#define _LOAD_CONST_INLINE_r23 1127 +#define _LOAD_CONST_INLINE_BORROW_r01 1128 +#define _LOAD_CONST_INLINE_BORROW_r12 1129 +#define _LOAD_CONST_INLINE_BORROW_r23 1130 +#define _LOAD_CONST_UNDER_INLINE_r02 1131 +#define _LOAD_CONST_UNDER_INLINE_r12 1132 +#define _LOAD_CONST_UNDER_INLINE_r23 1133 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1134 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1135 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1136 +#define _LOAD_DEREF_r01 1137 +#define _LOAD_FAST_r01 1138 +#define _LOAD_FAST_r12 1139 +#define _LOAD_FAST_r23 1140 +#define _LOAD_FAST_0_r01 1141 +#define _LOAD_FAST_0_r12 1142 +#define _LOAD_FAST_0_r23 1143 +#define _LOAD_FAST_1_r01 1144 +#define _LOAD_FAST_1_r12 1145 +#define _LOAD_FAST_1_r23 1146 +#define _LOAD_FAST_2_r01 1147 +#define _LOAD_FAST_2_r12 1148 +#define _LOAD_FAST_2_r23 1149 +#define _LOAD_FAST_3_r01 1150 +#define _LOAD_FAST_3_r12 1151 +#define _LOAD_FAST_3_r23 1152 +#define _LOAD_FAST_4_r01 1153 +#define _LOAD_FAST_4_r12 1154 +#define _LOAD_FAST_4_r23 1155 +#define _LOAD_FAST_5_r01 1156 +#define _LOAD_FAST_5_r12 1157 +#define _LOAD_FAST_5_r23 1158 +#define _LOAD_FAST_6_r01 1159 +#define _LOAD_FAST_6_r12 1160 +#define _LOAD_FAST_6_r23 1161 +#define _LOAD_FAST_7_r01 1162 +#define _LOAD_FAST_7_r12 1163 +#define _LOAD_FAST_7_r23 1164 +#define _LOAD_FAST_AND_CLEAR_r01 1165 +#define _LOAD_FAST_AND_CLEAR_r12 1166 +#define _LOAD_FAST_AND_CLEAR_r23 1167 +#define _LOAD_FAST_BORROW_r01 1168 +#define _LOAD_FAST_BORROW_r12 1169 +#define _LOAD_FAST_BORROW_r23 1170 +#define _LOAD_FAST_BORROW_0_r01 1171 +#define _LOAD_FAST_BORROW_0_r12 1172 +#define _LOAD_FAST_BORROW_0_r23 1173 +#define _LOAD_FAST_BORROW_1_r01 1174 +#define _LOAD_FAST_BORROW_1_r12 1175 +#define _LOAD_FAST_BORROW_1_r23 1176 +#define _LOAD_FAST_BORROW_2_r01 1177 +#define _LOAD_FAST_BORROW_2_r12 1178 +#define _LOAD_FAST_BORROW_2_r23 1179 +#define _LOAD_FAST_BORROW_3_r01 1180 +#define _LOAD_FAST_BORROW_3_r12 1181 +#define _LOAD_FAST_BORROW_3_r23 1182 +#define _LOAD_FAST_BORROW_4_r01 1183 +#define _LOAD_FAST_BORROW_4_r12 1184 +#define _LOAD_FAST_BORROW_4_r23 1185 +#define _LOAD_FAST_BORROW_5_r01 1186 +#define _LOAD_FAST_BORROW_5_r12 1187 +#define _LOAD_FAST_BORROW_5_r23 1188 +#define _LOAD_FAST_BORROW_6_r01 1189 +#define _LOAD_FAST_BORROW_6_r12 1190 +#define _LOAD_FAST_BORROW_6_r23 1191 +#define _LOAD_FAST_BORROW_7_r01 1192 +#define _LOAD_FAST_BORROW_7_r12 1193 +#define _LOAD_FAST_BORROW_7_r23 1194 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1195 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1196 +#define _LOAD_FAST_CHECK_r01 1197 +#define _LOAD_FAST_CHECK_r12 1198 +#define _LOAD_FAST_CHECK_r23 1199 +#define _LOAD_FAST_LOAD_FAST_r02 1200 +#define _LOAD_FAST_LOAD_FAST_r13 1201 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1202 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1203 +#define _LOAD_GLOBAL_r00 1204 +#define _LOAD_GLOBAL_BUILTINS_r01 1205 +#define _LOAD_GLOBAL_MODULE_r01 1206 +#define _LOAD_LOCALS_r01 1207 +#define _LOAD_LOCALS_r12 1208 +#define _LOAD_LOCALS_r23 1209 +#define _LOAD_NAME_r01 1210 +#define _LOAD_SMALL_INT_r01 1211 +#define _LOAD_SMALL_INT_r12 1212 +#define _LOAD_SMALL_INT_r23 1213 +#define _LOAD_SMALL_INT_0_r01 1214 +#define _LOAD_SMALL_INT_0_r12 1215 +#define _LOAD_SMALL_INT_0_r23 1216 +#define _LOAD_SMALL_INT_1_r01 1217 +#define _LOAD_SMALL_INT_1_r12 1218 +#define _LOAD_SMALL_INT_1_r23 1219 +#define _LOAD_SMALL_INT_2_r01 1220 +#define _LOAD_SMALL_INT_2_r12 1221 +#define _LOAD_SMALL_INT_2_r23 1222 +#define _LOAD_SMALL_INT_3_r01 1223 +#define _LOAD_SMALL_INT_3_r12 1224 +#define _LOAD_SMALL_INT_3_r23 1225 +#define _LOAD_SPECIAL_r00 1226 +#define _LOAD_SUPER_ATTR_ATTR_r31 1227 +#define _LOAD_SUPER_ATTR_METHOD_r32 1228 +#define _MAKE_CALLARGS_A_TUPLE_r33 1229 +#define _MAKE_CELL_r00 1230 +#define _MAKE_FUNCTION_r11 1231 +#define _MAKE_WARM_r00 1232 +#define _MAKE_WARM_r11 1233 +#define _MAKE_WARM_r22 1234 +#define _MAKE_WARM_r33 1235 +#define _MAP_ADD_r20 1236 +#define _MATCH_CLASS_r31 1237 +#define _MATCH_KEYS_r23 1238 +#define _MATCH_MAPPING_r02 1239 +#define _MATCH_MAPPING_r12 1240 +#define _MATCH_MAPPING_r23 1241 +#define _MATCH_SEQUENCE_r02 1242 +#define _MATCH_SEQUENCE_r12 1243 +#define _MATCH_SEQUENCE_r23 1244 +#define _MAYBE_EXPAND_METHOD_r00 1245 +#define _MAYBE_EXPAND_METHOD_KW_r11 1246 +#define _MONITOR_CALL_r00 1247 +#define _MONITOR_CALL_KW_r11 1248 +#define _MONITOR_JUMP_BACKWARD_r00 1249 +#define _MONITOR_JUMP_BACKWARD_r11 1250 +#define _MONITOR_JUMP_BACKWARD_r22 1251 +#define _MONITOR_JUMP_BACKWARD_r33 1252 +#define _MONITOR_RESUME_r00 1253 +#define _NOP_r00 1254 +#define _NOP_r11 1255 +#define _NOP_r22 1256 +#define _NOP_r33 1257 +#define _POP_CALL_r20 1258 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1259 +#define _POP_CALL_ONE_r30 1260 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1261 +#define _POP_CALL_TWO_r30 1262 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1263 +#define _POP_EXCEPT_r10 1264 +#define _POP_ITER_r20 1265 +#define _POP_JUMP_IF_FALSE_r00 1266 +#define _POP_JUMP_IF_FALSE_r10 1267 +#define _POP_JUMP_IF_FALSE_r21 1268 +#define _POP_JUMP_IF_FALSE_r32 1269 +#define _POP_JUMP_IF_TRUE_r00 1270 +#define _POP_JUMP_IF_TRUE_r10 1271 +#define _POP_JUMP_IF_TRUE_r21 1272 +#define _POP_JUMP_IF_TRUE_r32 1273 +#define _POP_TOP_r10 1274 +#define _POP_TOP_FLOAT_r00 1275 +#define _POP_TOP_FLOAT_r10 1276 +#define _POP_TOP_FLOAT_r21 1277 +#define _POP_TOP_FLOAT_r32 1278 +#define _POP_TOP_INT_r00 1279 +#define _POP_TOP_INT_r10 1280 +#define _POP_TOP_INT_r21 1281 +#define _POP_TOP_INT_r32 1282 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1283 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1284 +#define _POP_TOP_NOP_r00 1285 +#define _POP_TOP_NOP_r10 1286 +#define _POP_TOP_NOP_r21 1287 +#define _POP_TOP_NOP_r32 1288 +#define _POP_TOP_UNICODE_r00 1289 +#define _POP_TOP_UNICODE_r10 1290 +#define _POP_TOP_UNICODE_r21 1291 +#define _POP_TOP_UNICODE_r32 1292 +#define _POP_TWO_r20 1293 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1294 +#define _PUSH_EXC_INFO_r02 1295 +#define _PUSH_EXC_INFO_r12 1296 +#define _PUSH_EXC_INFO_r23 1297 +#define _PUSH_FRAME_r10 1298 +#define _PUSH_NULL_r01 1299 +#define _PUSH_NULL_r12 1300 +#define _PUSH_NULL_r23 1301 +#define _PUSH_NULL_CONDITIONAL_r00 1302 +#define _PY_FRAME_EX_r31 1303 +#define _PY_FRAME_GENERAL_r01 1304 +#define _PY_FRAME_KW_r11 1305 +#define _QUICKEN_RESUME_r00 1306 +#define _QUICKEN_RESUME_r11 1307 +#define _QUICKEN_RESUME_r22 1308 +#define _QUICKEN_RESUME_r33 1309 +#define _REPLACE_WITH_TRUE_r02 1310 +#define _REPLACE_WITH_TRUE_r12 1311 +#define _REPLACE_WITH_TRUE_r23 1312 +#define _RESUME_CHECK_r00 1313 +#define _RESUME_CHECK_r11 1314 +#define _RESUME_CHECK_r22 1315 +#define _RESUME_CHECK_r33 1316 +#define _RETURN_GENERATOR_r01 1317 +#define _RETURN_VALUE_r11 1318 +#define _SAVE_RETURN_OFFSET_r00 1319 +#define _SAVE_RETURN_OFFSET_r11 1320 +#define _SAVE_RETURN_OFFSET_r22 1321 +#define _SAVE_RETURN_OFFSET_r33 1322 +#define _SEND_r22 1323 +#define _SEND_GEN_FRAME_r22 1324 +#define _SETUP_ANNOTATIONS_r00 1325 +#define _SET_ADD_r10 1326 +#define _SET_FUNCTION_ATTRIBUTE_r01 1327 +#define _SET_FUNCTION_ATTRIBUTE_r11 1328 +#define _SET_FUNCTION_ATTRIBUTE_r21 1329 +#define _SET_FUNCTION_ATTRIBUTE_r32 1330 +#define _SET_IP_r00 1331 +#define _SET_IP_r11 1332 +#define _SET_IP_r22 1333 +#define _SET_IP_r33 1334 +#define _SET_UPDATE_r10 1335 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1336 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1337 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1338 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1339 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1340 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1341 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1342 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1343 +#define _SPILL_OR_RELOAD_r01 1344 +#define _SPILL_OR_RELOAD_r02 1345 +#define _SPILL_OR_RELOAD_r03 1346 +#define _SPILL_OR_RELOAD_r10 1347 +#define _SPILL_OR_RELOAD_r12 1348 +#define _SPILL_OR_RELOAD_r13 1349 +#define _SPILL_OR_RELOAD_r20 1350 +#define _SPILL_OR_RELOAD_r21 1351 +#define _SPILL_OR_RELOAD_r23 1352 +#define _SPILL_OR_RELOAD_r30 1353 +#define _SPILL_OR_RELOAD_r31 1354 +#define _SPILL_OR_RELOAD_r32 1355 +#define _START_EXECUTOR_r00 1356 +#define _STORE_ATTR_r20 1357 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1358 +#define _STORE_ATTR_SLOT_r21 1359 +#define _STORE_ATTR_WITH_HINT_r21 1360 +#define _STORE_DEREF_r10 1361 +#define _STORE_FAST_LOAD_FAST_r11 1362 +#define _STORE_FAST_STORE_FAST_r20 1363 +#define _STORE_GLOBAL_r10 1364 +#define _STORE_NAME_r10 1365 +#define _STORE_SLICE_r30 1366 +#define _STORE_SUBSCR_r30 1367 +#define _STORE_SUBSCR_DICT_r31 1368 +#define _STORE_SUBSCR_LIST_INT_r32 1369 +#define _SWAP_r11 1370 +#define _SWAP_2_r02 1371 +#define _SWAP_2_r12 1372 +#define _SWAP_2_r22 1373 +#define _SWAP_2_r33 1374 +#define _SWAP_3_r03 1375 +#define _SWAP_3_r13 1376 +#define _SWAP_3_r23 1377 +#define _SWAP_3_r33 1378 +#define _SWAP_FAST_r01 1379 +#define _SWAP_FAST_r11 1380 +#define _SWAP_FAST_r22 1381 +#define _SWAP_FAST_r33 1382 +#define _SWAP_FAST_0_r01 1383 +#define _SWAP_FAST_0_r11 1384 +#define _SWAP_FAST_0_r22 1385 +#define _SWAP_FAST_0_r33 1386 +#define _SWAP_FAST_1_r01 1387 +#define _SWAP_FAST_1_r11 1388 +#define _SWAP_FAST_1_r22 1389 +#define _SWAP_FAST_1_r33 1390 +#define _SWAP_FAST_2_r01 1391 +#define _SWAP_FAST_2_r11 1392 +#define _SWAP_FAST_2_r22 1393 +#define _SWAP_FAST_2_r33 1394 +#define _SWAP_FAST_3_r01 1395 +#define _SWAP_FAST_3_r11 1396 +#define _SWAP_FAST_3_r22 1397 +#define _SWAP_FAST_3_r33 1398 +#define _SWAP_FAST_4_r01 1399 +#define _SWAP_FAST_4_r11 1400 +#define _SWAP_FAST_4_r22 1401 +#define _SWAP_FAST_4_r33 1402 +#define _SWAP_FAST_5_r01 1403 +#define _SWAP_FAST_5_r11 1404 +#define _SWAP_FAST_5_r22 1405 +#define _SWAP_FAST_5_r33 1406 +#define _SWAP_FAST_6_r01 1407 +#define _SWAP_FAST_6_r11 1408 +#define _SWAP_FAST_6_r22 1409 +#define _SWAP_FAST_6_r33 1410 +#define _SWAP_FAST_7_r01 1411 +#define _SWAP_FAST_7_r11 1412 +#define _SWAP_FAST_7_r22 1413 +#define _SWAP_FAST_7_r33 1414 +#define _TIER2_RESUME_CHECK_r00 1415 +#define _TIER2_RESUME_CHECK_r11 1416 +#define _TIER2_RESUME_CHECK_r22 1417 +#define _TIER2_RESUME_CHECK_r33 1418 +#define _TO_BOOL_r11 1419 +#define _TO_BOOL_BOOL_r01 1420 +#define _TO_BOOL_BOOL_r11 1421 +#define _TO_BOOL_BOOL_r22 1422 +#define _TO_BOOL_BOOL_r33 1423 +#define _TO_BOOL_INT_r02 1424 +#define _TO_BOOL_INT_r12 1425 +#define _TO_BOOL_INT_r23 1426 +#define _TO_BOOL_LIST_r02 1427 +#define _TO_BOOL_LIST_r12 1428 +#define _TO_BOOL_LIST_r23 1429 +#define _TO_BOOL_NONE_r01 1430 +#define _TO_BOOL_NONE_r11 1431 +#define _TO_BOOL_NONE_r22 1432 +#define _TO_BOOL_NONE_r33 1433 +#define _TO_BOOL_STR_r02 1434 +#define _TO_BOOL_STR_r12 1435 +#define _TO_BOOL_STR_r23 1436 +#define _TRACE_RECORD_r00 1437 +#define _UNARY_INVERT_r12 1438 +#define _UNARY_NEGATIVE_r12 1439 +#define _UNARY_NOT_r01 1440 +#define _UNARY_NOT_r11 1441 +#define _UNARY_NOT_r22 1442 +#define _UNARY_NOT_r33 1443 +#define _UNPACK_EX_r10 1444 +#define _UNPACK_SEQUENCE_r10 1445 +#define _UNPACK_SEQUENCE_LIST_r10 1446 +#define _UNPACK_SEQUENCE_TUPLE_r10 1447 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1448 +#define _WITH_EXCEPT_START_r33 1449 +#define _YIELD_VALUE_r11 1450 +#define MAX_UOP_REGS_ID 1450 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 85f2948ece4b4d..0835ee5c9499d1 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -370,6 +370,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_TIER2_RESUME_CHECK] = HAS_PERIODIC_FLAG, [_COLD_EXIT] = HAS_SYNC_SP_FLAG, [_COLD_DYNAMIC_EXIT] = HAS_SYNC_SP_FLAG, + [_GUARD_CODE] = HAS_EXIT_FLAG, [_GUARD_IP__PUSH_FRAME] = HAS_EXIT_FLAG, [_GUARD_IP_YIELD_VALUE] = HAS_EXIT_FLAG, [_GUARD_IP_RETURN_VALUE] = HAS_EXIT_FLAG, @@ -377,10 +378,11 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_RECORD_TOS] = HAS_RECORDS_VALUE_FLAG, [_RECORD_TOS_TYPE] = HAS_RECORDS_VALUE_FLAG, [_RECORD_NOS] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_NOS_GEN_FUNC] = HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG, [_RECORD_4OS] = HAS_RECORDS_VALUE_FLAG, [_RECORD_CALLABLE] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG, [_RECORD_BOUND_METHOD] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG, - [_RECORD_CALLER_CODE] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_CODE] = HAS_RECORDS_VALUE_FLAG, }; const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = { @@ -3402,6 +3404,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, + [_GUARD_CODE] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_CODE_r00 }, + { 1, 1, _GUARD_CODE_r11 }, + { 2, 2, _GUARD_CODE_r22 }, + { 3, 3, _GUARD_CODE_r33 }, + }, + }, [_GUARD_IP__PUSH_FRAME] = { .best = { 0, 1, 2, 3 }, .entries = { @@ -4210,6 +4221,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_TIER2_RESUME_CHECK_r33] = _TIER2_RESUME_CHECK, [_COLD_EXIT_r00] = _COLD_EXIT, [_COLD_DYNAMIC_EXIT_r00] = _COLD_DYNAMIC_EXIT, + [_GUARD_CODE_r00] = _GUARD_CODE, + [_GUARD_CODE_r11] = _GUARD_CODE, + [_GUARD_CODE_r22] = _GUARD_CODE, + [_GUARD_CODE_r33] = _GUARD_CODE, [_GUARD_IP__PUSH_FRAME_r00] = _GUARD_IP__PUSH_FRAME, [_GUARD_IP__PUSH_FRAME_r11] = _GUARD_IP__PUSH_FRAME, [_GUARD_IP__PUSH_FRAME_r22] = _GUARD_IP__PUSH_FRAME, @@ -4640,6 +4655,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_GUARD_CALLABLE_TYPE_1_r13] = "_GUARD_CALLABLE_TYPE_1_r13", [_GUARD_CALLABLE_TYPE_1_r23] = "_GUARD_CALLABLE_TYPE_1_r23", [_GUARD_CALLABLE_TYPE_1_r33] = "_GUARD_CALLABLE_TYPE_1_r33", + [_GUARD_CODE] = "_GUARD_CODE", + [_GUARD_CODE_r00] = "_GUARD_CODE_r00", + [_GUARD_CODE_r11] = "_GUARD_CODE_r11", + [_GUARD_CODE_r22] = "_GUARD_CODE_r22", + [_GUARD_CODE_r33] = "_GUARD_CODE_r33", [_GUARD_DORV_NO_DICT] = "_GUARD_DORV_NO_DICT", [_GUARD_DORV_NO_DICT_r01] = "_GUARD_DORV_NO_DICT_r01", [_GUARD_DORV_NO_DICT_r11] = "_GUARD_DORV_NO_DICT_r11", @@ -5179,8 +5199,9 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_RECORD_4OS] = "_RECORD_4OS", [_RECORD_BOUND_METHOD] = "_RECORD_BOUND_METHOD", [_RECORD_CALLABLE] = "_RECORD_CALLABLE", - [_RECORD_CALLER_CODE] = "_RECORD_CALLER_CODE", + [_RECORD_CODE] = "_RECORD_CODE", [_RECORD_NOS] = "_RECORD_NOS", + [_RECORD_NOS_GEN_FUNC] = "_RECORD_NOS_GEN_FUNC", [_RECORD_TOS] = "_RECORD_TOS", [_RECORD_TOS_TYPE] = "_RECORD_TOS_TYPE", [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", @@ -6049,6 +6070,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _COLD_DYNAMIC_EXIT: return 0; + case _GUARD_CODE: + return 0; case _GUARD_IP__PUSH_FRAME: return 0; case _GUARD_IP_YIELD_VALUE: @@ -6063,13 +6086,15 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _RECORD_NOS: return 0; + case _RECORD_NOS_GEN_FUNC: + return 0; case _RECORD_4OS: return 0; case _RECORD_CALLABLE: return 0; case _RECORD_BOUND_METHOD: return 0; - case _RECORD_CALLER_CODE: + case _RECORD_CODE: return 0; default: return -1; diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 437cc340fc90e3..43b268b0206a46 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -978,50 +978,6 @@ def return_tenth(): # Constant narrowing allows constant folding for second comparison self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1) - def test_compare_str_eq_narrows_to_constant(self): - def f(n): - def return_hello(): - return "hello" - - hits = 0 - v = return_hello() - for _ in range(n): - if v == "hello": - if v == "hello": - hits += 1 - return hits - - res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) - self.assertEqual(res, TIER2_THRESHOLD) - self.assertIsNotNone(ex) - uops = get_opnames(ex) - - # Constant narrowing allows constant folding for second comparison - self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) - - def test_compare_str_ne_narrows_to_constant(self): - def f(n): - def return_hello(): - return "hello" - - hits = 0 - v = return_hello() - for _ in range(n): - if v != "hello": - hits += 1000 - else: - if v == "hello": - hits += 1 - return hits - - res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) - self.assertEqual(res, TIER2_THRESHOLD) - self.assertIsNotNone(ex) - uops = get_opnames(ex) - - # Constant narrowing allows constant folding for second comparison - self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) - def test_combine_stack_space_checks_sequential(self): def dummy12(x): return x - 1 diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index 64c9ffeb4dc411..c89c790988c52d 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -749,11 +749,11 @@ JUMP_TO_PREDICTED(BINARY_OP); } getitem = PyStackRef_FromPyObjectNew(getitem_o); - STAT_INC(BINARY_OP, hit); } // _BINARY_OP_SUBSCR_INIT_CALL { sub = stack_pointer[-1]; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -10449,33 +10449,30 @@ next_instr += 1; INSTRUCTION_STATS(RETURN_GENERATOR); _PyStackRef res; - // _RETURN_GENERATOR - { - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (gen == NULL) { - JUMP_TO_LABEL(error); - } - assert(STACK_LEVEL() <= 2); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; - frame->instr_ptr++; - _PyFrame_Copy(frame, gen_frame); - assert(frame->frame_obj == NULL); - gen->gi_frame_state = FRAME_CREATED; - gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *prev = frame->previous; - _PyThreadState_PopFrame(tstate, frame); - frame = tstate->current_frame = prev; - LOAD_IP(frame->return_offset); - stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); - LLTRACE_RESUME_FRAME(); + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) { + JUMP_TO_LABEL(error); } + assert(STACK_LEVEL() <= 2); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; + frame->instr_ptr++; + _PyFrame_Copy(frame, gen_frame); + assert(frame->frame_obj == NULL); + gen->gi_frame_state = FRAME_CREATED; + gen_frame->owner = FRAME_OWNED_BY_GENERATOR; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + frame = tstate->current_frame = prev; + LOAD_IP(frame->return_offset); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); + LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -10492,24 +10489,21 @@ INSTRUCTION_STATS(RETURN_VALUE); _PyStackRef retval; _PyStackRef res; - // _RETURN_VALUE - { - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - assert(STACK_LEVEL() == 0); - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *dying = frame; - frame = tstate->current_frame = dying->previous; - _PyEval_FrameClearAndPop(tstate, dying); - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(frame->return_offset); - res = temp; - LLTRACE_RESUME_FRAME(); - } + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(STACK_LEVEL() == 0); + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *dying = frame; + frame = tstate->current_frame = dying->previous; + _PyEval_FrameClearAndPop(tstate, dying); + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(frame->return_offset); + res = temp; + LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -12326,40 +12320,37 @@ INSTRUCTION_STATS(YIELD_VALUE); _PyStackRef retval; _PyStackRef value; - // _YIELD_VALUE - { - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); - assert(oparg == 0 || oparg == 1); - _PyStackRef temp = retval; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - tstate->exc_info = gen->gi_exc_state.previous_item; - gen->gi_exc_state.previous_item = NULL; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *gen_frame = frame; - frame = tstate->current_frame = frame->previous; - gen_frame->previous = NULL; - ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; - FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); - assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); + assert(oparg == 0 || oparg == 1); + _PyStackRef temp = retval; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = tstate->current_frame = frame->previous; + gen_frame->previous = NULL; + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); + assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); + #if TIER_ONE + assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); - #endif - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - value = PyStackRef_MakeHeapSafe(temp); - LLTRACE_RESUME_FRAME(); - } + #endif + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); + value = PyStackRef_MakeHeapSafe(temp); + LLTRACE_RESUME_FRAME(); stack_pointer[0] = value; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index a990ab28577c73..a014f56deb202e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1095,10 +1095,10 @@ dummy_func( assert(code->co_argcount == 2); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, code->co_framesize)); getitem = PyStackRef_FromPyObjectNew(getitem_o); - STAT_INC(BINARY_OP, hit); } op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) { + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -1108,7 +1108,7 @@ dummy_func( } macro(BINARY_OP_SUBSCR_GETITEM) = - _RECORD_TOS + + _RECORD_NOS + unused/5 + // Skip over the counter and cache _CHECK_PEP_523 + _BINARY_OP_SUBSCR_CHECK_FUNC + @@ -1269,7 +1269,7 @@ dummy_func( // The stack effect here is a bit misleading. // retval is popped from the stack, but res // is pushed to a different frame, the callers' frame. - op(_RETURN_VALUE, (retval -- res)) { + inst(RETURN_VALUE, (retval -- res)) { assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); DEAD(retval); @@ -1293,13 +1293,9 @@ dummy_func( ERROR_IF(err); } - macro(RETURN_VALUE) = - _RECORD_CALLER_CODE + - _RETURN_VALUE; - macro(INSTRUMENTED_RETURN_VALUE) = _RETURN_VALUE_EVENT + - _RETURN_VALUE; + RETURN_VALUE; inst(GET_AITER, (obj -- iter)) { unaryfunc getter = NULL; @@ -1436,11 +1432,12 @@ dummy_func( macro(SEND_GEN) = unused/1 + + _RECORD_NOS_GEN_FUNC + _CHECK_PEP_523 + _SEND_GEN_FRAME + _PUSH_FRAME; - op(_YIELD_VALUE, (retval -- value)) { + inst(YIELD_VALUE, (retval -- value)) { // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1476,10 +1473,6 @@ dummy_func( LLTRACE_RESUME_FRAME(); } - macro(YIELD_VALUE) = - _RECORD_CALLER_CODE + - _YIELD_VALUE; - tier1 op(_YIELD_VALUE_EVENT, (val -- val)) { int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, @@ -1495,7 +1488,7 @@ dummy_func( macro(INSTRUMENTED_YIELD_VALUE) = _YIELD_VALUE_EVENT + - _YIELD_VALUE; + YIELD_VALUE; inst(POP_EXCEPT, (exc_value -- )) { _PyErr_StackItem *exc_info = tstate->exc_info; @@ -3523,7 +3516,7 @@ dummy_func( } macro(FOR_ITER_GEN) = - _RECORD_NOS + + _RECORD_NOS_GEN_FUNC + unused/1 + _CHECK_PEP_523 + _FOR_ITER_GEN_FRAME + @@ -5074,7 +5067,7 @@ dummy_func( *ptr = attr; } - op(_RETURN_GENERATOR, (-- res)) { + inst(RETURN_GENERATOR, (-- res)) { assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -5097,10 +5090,6 @@ dummy_func( LLTRACE_RESUME_FRAME(); } - macro(RETURN_GENERATOR) = - _RECORD_CALLER_CODE + - _RETURN_GENERATOR; - inst(BUILD_SLICE, (args[oparg] -- slice)) { PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); @@ -5646,6 +5635,12 @@ dummy_func( Py_UNREACHABLE(); } + tier2 op(_GUARD_CODE, (version/2 -- )) { + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + EXIT_IF(code == Py_None); + EXIT_IF(((PyCodeObject *)code)->co_version != version); + } + tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) { _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { @@ -5694,6 +5689,14 @@ dummy_func( RECORD_VALUE(PyStackRef_AsPyObjectBorrow(nos)); } + tier2 op(_RECORD_NOS_GEN_FUNC, (nos, tos -- nos, tos)) { + PyObject *obj = PyStackRef_AsPyObjectBorrow(nos); + if (PyGen_Check(obj)) { + PyObject *func = (PyObject *)_PyFrame_GetFunction(&((PyGenObject *)obj)->gi_iframe); + RECORD_VALUE(func); + } + } + tier2 op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) { RECORD_VALUE(PyStackRef_AsPyObjectBorrow(value)); } @@ -5710,12 +5713,9 @@ dummy_func( } } - tier2 op(_RECORD_CALLER_CODE, ( -- )) { - _PyInterpreterFrame *caller_frame = frame->previous; - if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) { - PyCodeObject *code = _PyFrame_GetCode(frame->previous); - RECORD_VALUE(code); - } + /* Inserted by the JIT tracer. Never executed. */ + tier2 op(_RECORD_CODE, ( -- )) { + RECORD_VALUE(NULL); } label(pop_2_error) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9c82f1acdef493..08c547c4a0a3b4 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -6184,7 +6184,6 @@ JUMP_TO_JUMP_TARGET(); } getitem = PyStackRef_FromPyObjectNew(getitem_o); - STAT_INC(BINARY_OP, hit); _tos_cache2 = getitem; _tos_cache1 = _stack_item_1; _tos_cache0 = container; @@ -6203,6 +6202,7 @@ getitem = stack_pointer[-1]; sub = stack_pointer[-2]; container = stack_pointer[-3]; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -6227,6 +6227,7 @@ getitem = _stack_item_0; sub = stack_pointer[-1]; container = stack_pointer[-2]; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -6252,6 +6253,7 @@ getitem = _stack_item_1; sub = _stack_item_0; container = stack_pointer[-1]; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -6278,6 +6280,7 @@ getitem = _stack_item_2; sub = _stack_item_1; container = _stack_item_0; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -20142,6 +20145,110 @@ GOTO_TIER_ONE(target); } + case _GUARD_CODE_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + uint32_t version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (code == Py_None) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + if (((PyCodeObject *)code)->co_version != version) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CODE_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + uint32_t version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (code == Py_None) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + if (((PyCodeObject *)code)->co_version != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CODE_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + uint32_t version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (code == Py_None) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + if (((PyCodeObject *)code)->co_version != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_CODE_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + uint32_t version = (uint32_t)CURRENT_OPERAND0_32(); + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + if (code == Py_None) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + if (((PyCodeObject *)code)->co_version != version) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _GUARD_IP__PUSH_FRAME_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index d3c5f526efd6a8..be5dbfcc747935 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -749,11 +749,11 @@ JUMP_TO_PREDICTED(BINARY_OP); } getitem = PyStackRef_FromPyObjectNew(getitem_o); - STAT_INC(BINARY_OP, hit); } // _BINARY_OP_SUBSCR_INIT_CALL { sub = stack_pointer[-1]; + STAT_INC(BINARY_OP, hit); _PyInterpreterFrame* pushed_frame = _PyFrame_PushUnchecked(tstate, getitem, 2, frame); pushed_frame->localsplus[0] = container; pushed_frame->localsplus[1] = sub; @@ -10446,33 +10446,30 @@ next_instr += 1; INSTRUCTION_STATS(RETURN_GENERATOR); _PyStackRef res; - // _RETURN_GENERATOR - { - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (gen == NULL) { - JUMP_TO_LABEL(error); - } - assert(STACK_LEVEL() <= 2); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; - frame->instr_ptr++; - _PyFrame_Copy(frame, gen_frame); - assert(frame->frame_obj == NULL); - gen->gi_frame_state = FRAME_CREATED; - gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *prev = frame->previous; - _PyThreadState_PopFrame(tstate, frame); - frame = tstate->current_frame = prev; - LOAD_IP(frame->return_offset); - stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); - LLTRACE_RESUME_FRAME(); + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) { + JUMP_TO_LABEL(error); } + assert(STACK_LEVEL() <= 2); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; + frame->instr_ptr++; + _PyFrame_Copy(frame, gen_frame); + assert(frame->frame_obj == NULL); + gen->gi_frame_state = FRAME_CREATED; + gen_frame->owner = FRAME_OWNED_BY_GENERATOR; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + frame = tstate->current_frame = prev; + LOAD_IP(frame->return_offset); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); + LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -10489,24 +10486,21 @@ INSTRUCTION_STATS(RETURN_VALUE); _PyStackRef retval; _PyStackRef res; - // _RETURN_VALUE - { - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - assert(STACK_LEVEL() == 0); - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *dying = frame; - frame = tstate->current_frame = dying->previous; - _PyEval_FrameClearAndPop(tstate, dying); - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(frame->return_offset); - res = temp; - LLTRACE_RESUME_FRAME(); - } + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(STACK_LEVEL() == 0); + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *dying = frame; + frame = tstate->current_frame = dying->previous; + _PyEval_FrameClearAndPop(tstate, dying); + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(frame->return_offset); + res = temp; + LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -12323,40 +12317,37 @@ INSTRUCTION_STATS(YIELD_VALUE); _PyStackRef retval; _PyStackRef value; - // _YIELD_VALUE - { - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); - assert(oparg == 0 || oparg == 1); - _PyStackRef temp = retval; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - tstate->exc_info = gen->gi_exc_state.previous_item; - gen->gi_exc_state.previous_item = NULL; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *gen_frame = frame; - frame = tstate->current_frame = frame->previous; - gen_frame->previous = NULL; - ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; - FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); - assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); + assert(oparg == 0 || oparg == 1); + _PyStackRef temp = retval; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = tstate->current_frame = frame->previous; + gen_frame->previous = NULL; + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); + assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); + #if TIER_ONE + assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); - #endif - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - value = PyStackRef_MakeHeapSafe(temp); - LLTRACE_RESUME_FRAME(); - } + #endif + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); + value = PyStackRef_MakeHeapSafe(temp); + LLTRACE_RESUME_FRAME(); stack_pointer[0] = value; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); diff --git a/Python/optimizer.c b/Python/optimizer.c index e4e18f14bdc9b1..bf5d8a28264635 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -928,22 +928,8 @@ _PyJit_translate_single_bytecode_to_trace( } if (uop == _PUSH_FRAME || uop == _RETURN_VALUE || uop == _RETURN_GENERATOR || uop == _YIELD_VALUE) { PyCodeObject *new_code = (PyCodeObject *)PyStackRef_AsPyObjectBorrow(frame->f_executable); - PyFunctionObject *new_func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - - operand = 0; - if (frame->owner < FRAME_OWNED_BY_INTERPRETER) { - // Don't add nested code objects to the dependency. - // It causes endless re-traces. - if (new_func != NULL && !Py_IsNone((PyObject*)new_func) && !(new_code->co_flags & CO_NESTED)) { - operand = (uintptr_t)new_func; - DPRINTF(2, "Adding %p func to op\n", (void *)operand); - _Py_BloomFilter_Add(dependencies, new_func); - } - else if (new_code != NULL && !Py_IsNone((PyObject*)new_code)) { - operand = (uintptr_t)new_code | 1; - DPRINTF(2, "Adding %p code to op\n", (void *)operand); - _Py_BloomFilter_Add(dependencies, new_code); - } + if (new_code != NULL && !Py_IsNone((PyObject*)new_code)) { + _Py_BloomFilter_Add(dependencies, new_code); } ADD_TO_TRACE(uop, oparg, operand, target); uop_buffer_last(trace)->operand1 = PyStackRef_IsNone(frame->f_executable) ? 2 : ((int)(frame->stackpointer - _PyFrame_Stackbase(frame))); @@ -974,7 +960,13 @@ _PyJit_translate_single_bytecode_to_trace( DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[uop_buffer_last(trace)->opcode]); Py_UNREACHABLE(); } + PyObject *code = PyStackRef_AsPyObjectBorrow(frame->f_executable); + Py_INCREF(code); + ADD_TO_TRACE(_RECORD_CODE, 0, (uintptr_t)code, 0); ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0); + if (PyCode_Check(code)) { + ADD_TO_TRACE(_GUARD_CODE, 0, ((PyCodeObject *)code)->co_version, 0); + } } // Loop back to the start int is_first_instr = tracer->initial_state.close_loop_instr == next_instr || @@ -1224,7 +1216,8 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length) base_opcode == _GUARD_IP__PUSH_FRAME || base_opcode == _GUARD_IP_RETURN_VALUE || base_opcode == _GUARD_IP_YIELD_VALUE || - base_opcode == _GUARD_IP_RETURN_GENERATOR + base_opcode == _GUARD_IP_RETURN_GENERATOR || + base_opcode == _GUARD_CODE ) { base_exit_op = _DYNAMIC_EXIT; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 039aacf23ae3a3..381b2500158ef0 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -226,6 +226,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, uint16_t opcode, uint16_t oparg, uintptr_t operand0) { _PyUOpInstruction *out = ctx->out_buffer.next; + assert(out < ctx->out_buffer.end); out->opcode = (opcode); out->format = this_instr->format; out->oparg = (oparg); @@ -261,6 +262,7 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_bottom _Py_uop_sym_is_bottom #define sym_truthiness _Py_uop_sym_truthiness #define frame_new _Py_uop_frame_new +#define frame_new_from_symbol _Py_uop_frame_new_from_symbol #define frame_pop _Py_uop_frame_pop #define sym_new_tuple _Py_uop_sym_new_tuple #define sym_tuple_getitem _Py_uop_sym_tuple_getitem @@ -271,6 +273,11 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_new_truthiness _Py_uop_sym_new_truthiness #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing +#define sym_set_recorded_type(SYM, TYPE) _Py_uop_sym_set_recorded_type(ctx, SYM, TYPE) +#define sym_set_recorded_value(SYM, VAL) _Py_uop_sym_set_recorded_value(ctx, SYM, VAL) +#define sym_set_recorded_gen_func(SYM, VAL) _Py_uop_sym_set_recorded_gen_func(ctx, SYM, VAL) +#define sym_get_probable_func_code _Py_uop_sym_get_probable_func_code +#define sym_get_probable_value _Py_uop_sym_get_probable_value /* Comparison oparg masks */ #define COMPARE_LT_MASK 2 @@ -355,30 +362,6 @@ lookup_attr(JitOptContext *ctx, _PyBloomFilter *dependencies, _PyUOpInstruction return sym_new_not_null(ctx); } -static PyCodeObject * -get_code_with_logging(_PyUOpInstruction *op) -{ - PyCodeObject *co = NULL; - uint64_t push_operand = op->operand0; - if (push_operand & 1) { - co = (PyCodeObject *)(push_operand & ~1); - DPRINTF(3, " code=%p\n", co); - assert(PyCode_Check(co)); - } - else { - PyFunctionObject *func = (PyFunctionObject *)push_operand; - DPRINTF(3, " func=%p ", func); - if (func == NULL) { - DPRINTF(3, "\n"); - DPRINTF(1, "Missing function\n"); - return NULL; - } - co = (PyCodeObject *)func->func_code; - DPRINTF(3, "code=%p\n", co); - } - return co; -} - static PyCodeObject * get_current_code_object(JitOptContext *ctx) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 89c6707160326c..0863d5dd8f8df7 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -30,6 +30,7 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_set_compact_int(SYM) _Py_uop_sym_set_compact_int(ctx, SYM) #define sym_is_bottom _Py_uop_sym_is_bottom #define frame_new _Py_uop_frame_new +#define frame_new_from_symbol _Py_uop_frame_new_from_symbol #define frame_pop _Py_uop_frame_pop #define sym_new_tuple _Py_uop_sym_new_tuple #define sym_tuple_getitem _Py_uop_sym_tuple_getitem @@ -40,6 +41,11 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_new_truthiness _Py_uop_sym_new_truthiness #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing +#define sym_set_recorded_type(SYM, TYPE) _Py_uop_sym_set_recorded_type(ctx, SYM, TYPE) +#define sym_set_recorded_value(SYM, VAL) _Py_uop_sym_set_recorded_value(ctx, SYM, VAL) +#define sym_set_recorded_gen_func(SYM, VAL) _Py_uop_sym_set_recorded_gen_func(ctx, SYM, VAL) +#define sym_get_probable_func_code _Py_uop_sym_get_probable_func_code +#define sym_get_probable_value _Py_uop_sym_get_probable_value extern int optimize_to_bool( @@ -337,14 +343,23 @@ dummy_func(void) { GETLOCAL(this_instr->operand0) = sym_new_null(ctx); } - op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) { - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging(this_instr + 1); - if (co == NULL) { - ctx->done = true; - break; + op(_BINARY_OP_SUBSCR_CHECK_FUNC, (container, unused -- container, unused, getitem)) { + getitem = sym_new_not_null(ctx); + PyTypeObject *tp = sym_get_type(container); + if (tp == NULL) { + PyObject *c = sym_get_probable_value(container); + if (c != NULL) { + tp = Py_TYPE(c); + } } - _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + if (tp != NULL) { + PyObject *getitem_o = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; + sym_set_recorded_value(getitem, getitem_o); + } + } + + op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) { + _Py_UOpsAbstractFrame *f = frame_new_from_symbol(ctx, getitem, 0, NULL, 0); if (f == NULL) { break; } @@ -556,17 +571,10 @@ dummy_func(void) { } op(_COMPARE_OP_STR, (left, right -- res, l, r)) { - int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); - - if (cmp_mask == COMPARE_EQ_MASK) { - res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); - } - else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { - res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); - } - else { - res = sym_new_type(ctx, &PyBool_Type); - } + /* Cannot use predicate optimization here, as `a == b` + * does not imply that `a` is equivalent to `b`. `a` may be + * mortal, while `b` is immortal */ + res = sym_new_type(ctx, &PyBool_Type); l = left; r = right; REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res); @@ -814,12 +822,8 @@ dummy_func(void) { op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame)) { // + 1 for _SAVE_RETURN_OFFSET - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging(this_instr + 2); - if (co == NULL) { - ctx->done = true; - break; - } + // FIX ME -- This needs a version check and function watcher + PyCodeObject *co = (PyCodeObject *)((PyFunctionObject *)fget)->func_code; _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); if (f == NULL) { break; @@ -872,14 +876,6 @@ dummy_func(void) { op(_INIT_CALL_PY_EXACT_ARGS, (callable, self_or_null, args[oparg] -- new_frame)) { int argcount = oparg; - - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - assert(!PyJitRef_IsNull(self_or_null)); assert(args != NULL); if (sym_is_not_null(self_or_null)) { @@ -889,9 +885,9 @@ dummy_func(void) { } if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, args, argcount)); } else { - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); } } @@ -902,36 +898,15 @@ dummy_func(void) { } op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame)) { - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); } op(_PY_FRAME_KW, (callable, self_or_null, args[oparg], kwnames -- new_frame)) { - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); } op(_PY_FRAME_EX, (func_st, null, callargs_st, kwargs_st -- ex_frame)) { - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - - ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + ex_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, func_st, 0, NULL, 0)); } op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { @@ -954,8 +929,7 @@ dummy_func(void) { ctx->frame = shim; ctx->curr_frame_depth++; assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1)); + init_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, init, 0, args-1, oparg+1)); } op(_RETURN_VALUE, (retval -- res)) { @@ -964,7 +938,9 @@ dummy_func(void) { DEAD(retval); SAVE_STACK(); ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -973,8 +949,8 @@ dummy_func(void) { if (ctx->curr_frame_depth >= 2) { PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code; if (expected_code == returning_code) { - assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE); - REPLACE_OP((this_instr + 1), _NOP, 0, 0); + assert(this_instr[2].opcode == _GUARD_IP_RETURN_VALUE); + REPLACE_OP((this_instr + 2), _NOP, 0, 0); } } if (frame_pop(ctx, returning_code, returning_stacklevel)) { @@ -989,7 +965,9 @@ dummy_func(void) { op(_RETURN_GENERATOR, ( -- res)) { SYNC_SP(); ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -1009,7 +987,9 @@ dummy_func(void) { DEAD(retval); SAVE_STACK(); ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -1035,14 +1015,8 @@ dummy_func(void) { } } - op(_FOR_ITER_GEN_FRAME, (unused, unused -- unused, unused, gen_frame)) { - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - if (co == NULL) { - ctx->done = true; - break; - } - _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0); + op(_FOR_ITER_GEN_FRAME, (iter, unused -- iter, unused, gen_frame)) { + _Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, iter, 1, NULL, 0); if (new_frame == NULL) { ctx->done = true; break; @@ -1051,14 +1025,8 @@ dummy_func(void) { gen_frame = PyJitRef_WrapInvalid(new_frame); } - op(_SEND_GEN_FRAME, (unused, v -- unused, gen_frame)) { - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - if (co == NULL) { - ctx->done = true; - break; - } - _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0); + op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame)) { + _Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, 1, NULL, 0); if (new_frame == NULL) { ctx->done = true; break; @@ -1067,9 +1035,8 @@ dummy_func(void) { gen_frame = PyJitRef_WrapInvalid(new_frame); } - op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { - assert((this_instr + 4)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 4)); + op(_CHECK_STACK_SPACE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { + PyCodeObject *co = sym_get_probable_func_code(callable); if (co == NULL) { ctx->done = true; break; @@ -1089,22 +1056,12 @@ dummy_func(void) { ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame); ctx->curr_frame_depth++; stack_pointer = ctx->frame->stack_pointer; - uint64_t operand = this_instr->operand0; - if (operand == 0) { - ctx->done = true; - break; - } - if (!(operand & 1)) { - PyFunctionObject *func = (PyFunctionObject *)operand; - // No need to re-add to dependencies here. Already - // handled by the tracer. - ctx->frame->func = func; - } // Fixed calls don't need IP guards. if ((this_instr-1)->opcode == _CREATE_INIT_FRAME) { assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME); REPLACE_OP(this_instr+1, _NOP, 0, 0); } + assert(ctx->frame->locals != NULL); } op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) { @@ -1653,6 +1610,32 @@ dummy_func(void) { ss = sub_st; } + op(_RECORD_TOS, (tos -- tos)) { + sym_set_recorded_value(tos, (PyObject *)this_instr->operand0); + } + + op(_RECORD_TOS_TYPE, (tos -- tos)) { + PyTypeObject *tp = (PyTypeObject *)this_instr->operand0; + sym_set_recorded_type(tos, tp); + } + + op(_RECORD_NOS, (nos, tos -- nos, tos)) { + sym_set_recorded_value(nos, (PyObject *)this_instr->operand0); + } + + op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) { + sym_set_recorded_value(value, (PyObject *)this_instr->operand0); + } + + op(_RECORD_CALLABLE, (func, self, args[oparg] -- func, self, args[oparg])) { + sym_set_recorded_value(func, (PyObject *)this_instr->operand0); + } + + op(_RECORD_NOS_GEN_FUNC, (nos, tos -- nos, tos)) { + PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0; + assert(func == NULL || PyFunction_Check(func)); + sym_set_recorded_gen_func(nos, func); + } // END BYTECODES // diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 61a30314c21789..9a51d2fa366661 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1115,8 +1115,21 @@ } case _BINARY_OP_SUBSCR_CHECK_FUNC: { + JitOptRef container; JitOptRef getitem; + container = stack_pointer[-2]; getitem = sym_new_not_null(ctx); + PyTypeObject *tp = sym_get_type(container); + if (tp == NULL) { + PyObject *c = sym_get_probable_value(container); + if (c != NULL) { + tp = Py_TYPE(c); + } + } + if (tp != NULL) { + PyObject *getitem_o = ((PyHeapTypeObject *)tp)->_spec_cache.getitem; + sym_set_recorded_value(getitem, getitem_o); + } CHECK_STACK_BOUNDS(1); stack_pointer[0] = getitem; stack_pointer += 1; @@ -1125,18 +1138,14 @@ } case _BINARY_OP_SUBSCR_INIT_CALL: { + JitOptRef getitem; JitOptRef sub; JitOptRef container; JitOptRef new_frame; + getitem = stack_pointer[-1]; sub = stack_pointer[-2]; container = stack_pointer[-3]; - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging(this_instr + 1); - if (co == NULL) { - ctx->done = true; - break; - } - _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + _Py_UOpsAbstractFrame *f = frame_new_from_symbol(ctx, getitem, 0, NULL, 0); if (f == NULL) { break; } @@ -1239,7 +1248,9 @@ stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -1248,8 +1259,8 @@ if (ctx->curr_frame_depth >= 2) { PyCodeObject *expected_code = ctx->frames[ctx->curr_frame_depth - 2].code; if (expected_code == returning_code) { - assert((this_instr + 1)->opcode == _GUARD_IP_RETURN_VALUE); - REPLACE_OP((this_instr + 1), _NOP, 0, 0); + assert(this_instr[2].opcode == _GUARD_IP_RETURN_VALUE); + REPLACE_OP((this_instr + 2), _NOP, 0, 0); } } if (frame_pop(ctx, returning_code, returning_stacklevel)) { @@ -1292,15 +1303,11 @@ case _SEND_GEN_FRAME: { JitOptRef v; + JitOptRef receiver; JitOptRef gen_frame; v = stack_pointer[-1]; - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - if (co == NULL) { - ctx->done = true; - break; - } - _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0); + receiver = stack_pointer[-2]; + _Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, receiver, 1, NULL, 0); if (new_frame == NULL) { ctx->done = true; break; @@ -1320,7 +1327,9 @@ stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -1984,12 +1993,7 @@ JitOptRef new_frame; owner = stack_pointer[-1]; PyObject *fget = (PyObject *)this_instr->operand0; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging(this_instr + 2); - if (co == NULL) { - ctx->done = true; - break; - } + PyCodeObject *co = (PyCodeObject *)((PyFunctionObject *)fget)->func_code; _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); if (f == NULL) { break; @@ -2267,16 +2271,7 @@ JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); - if (cmp_mask == COMPARE_EQ_MASK) { - res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); - } - else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { - res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); - } - else { - res = sym_new_type(ctx, &PyBool_Type); - } + res = sym_new_type(ctx, &PyBool_Type); l = left; r = right; if ( @@ -2694,14 +2689,10 @@ } case _FOR_ITER_GEN_FRAME: { + JitOptRef iter; JitOptRef gen_frame; - assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - if (co == NULL) { - ctx->done = true; - break; - } - _Py_UOpsAbstractFrame *new_frame = frame_new(ctx, co, 1, NULL, 0); + iter = stack_pointer[-2]; + _Py_UOpsAbstractFrame *new_frame = frame_new_from_symbol(ctx, iter, 1, NULL, 0); if (new_frame == NULL) { ctx->done = true; break; @@ -2884,14 +2875,10 @@ /* _MONITOR_CALL is not a viable micro-op for tier 2 */ case _PY_FRAME_GENERAL: { + JitOptRef callable; JitOptRef new_frame; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + callable = stack_pointer[-2 - oparg]; + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; stack_pointer += -1 - oparg; @@ -2996,8 +2983,9 @@ } case _CHECK_STACK_SPACE: { - assert((this_instr + 4)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 4)); + JitOptRef callable; + callable = stack_pointer[-2 - oparg]; + PyCodeObject *co = sym_get_probable_func_code(callable); if (co == NULL) { ctx->done = true; break; @@ -3013,16 +3001,12 @@ case _INIT_CALL_PY_EXACT_ARGS: { JitOptRef *args; JitOptRef self_or_null; + JitOptRef callable; JitOptRef new_frame; args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; int argcount = oparg; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } assert(!PyJitRef_IsNull(self_or_null)); assert(args != NULL); if (sym_is_not_null(self_or_null)) { @@ -3030,9 +3014,9 @@ argcount++; } if (sym_is_null(self_or_null) || sym_is_not_null(self_or_null)) { - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args, argcount)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, args, argcount)); } else { - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); } CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = new_frame; @@ -3053,19 +3037,11 @@ ctx->frame = (_Py_UOpsAbstractFrame *)PyJitRef_Unwrap(new_frame); ctx->curr_frame_depth++; stack_pointer = ctx->frame->stack_pointer; - uint64_t operand = this_instr->operand0; - if (operand == 0) { - ctx->done = true; - break; - } - if (!(operand & 1)) { - PyFunctionObject *func = (PyFunctionObject *)operand; - ctx->frame->func = func; - } if ((this_instr-1)->opcode == _CREATE_INIT_FRAME) { assert((this_instr+1)->opcode == _GUARD_IP__PUSH_FRAME); REPLACE_OP(this_instr+1, _NOP, 0, 0); } + assert(ctx->frame->locals != NULL); break; } @@ -3212,9 +3188,11 @@ case _CREATE_INIT_FRAME: { JitOptRef *args; JitOptRef self; + JitOptRef init; JitOptRef init_frame; args = &stack_pointer[-oparg]; self = stack_pointer[-1 - oparg]; + init = stack_pointer[-2 - oparg]; ctx->frame->stack_pointer = stack_pointer - oparg - 2; _Py_UOpsAbstractFrame *shim = frame_new(ctx, (PyCodeObject *)&_Py_InitCleanup, 0, NULL, 0); if (shim == NULL) { @@ -3226,8 +3204,7 @@ ctx->frame = shim; ctx->curr_frame_depth++; assert((this_instr + 1)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 1)); - init_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, args-1, oparg+1)); + init_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, init, 0, args-1, oparg+1)); CHECK_STACK_BOUNDS(-1 - oparg); stack_pointer[-2 - oparg] = init_frame; stack_pointer += -1 - oparg; @@ -3501,14 +3478,10 @@ /* _DO_CALL_KW is not a viable micro-op for tier 2 */ case _PY_FRAME_KW: { + JitOptRef callable; JitOptRef new_frame; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - new_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + callable = stack_pointer[-3 - oparg]; + new_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, callable, 0, NULL, 0)); CHECK_STACK_BOUNDS(-2 - oparg); stack_pointer[-3 - oparg] = new_frame; stack_pointer += -2 - oparg; @@ -3553,14 +3526,10 @@ } case _PY_FRAME_EX: { + JitOptRef func_st; JitOptRef ex_frame; - assert((this_instr + 2)->opcode == _PUSH_FRAME); - PyCodeObject *co = get_code_with_logging((this_instr + 2)); - if (co == NULL) { - ctx->done = true; - break; - } - ex_frame = PyJitRef_WrapInvalid(frame_new(ctx, co, 0, NULL, 0)); + func_st = stack_pointer[-4]; + ex_frame = PyJitRef_WrapInvalid(frame_new_from_symbol(ctx, func_st, 0, NULL, 0)); CHECK_STACK_BOUNDS(-3); stack_pointer[-4] = ex_frame; stack_pointer += -3; @@ -3602,7 +3571,9 @@ case _RETURN_GENERATOR: { JitOptRef res; ctx->frame->stack_pointer = stack_pointer; - PyCodeObject *returning_code = get_code_with_logging(this_instr); + assert(this_instr[1].opcode == _RECORD_CODE); + PyCodeObject *returning_code = (PyCodeObject *)this_instr[1].operand0; + assert(PyCode_Check(returning_code)); if (returning_code == NULL) { ctx->done = true; break; @@ -4167,6 +4138,10 @@ break; } + case _GUARD_CODE: { + break; + } + case _GUARD_IP__PUSH_FRAME: { break; } @@ -4184,22 +4159,47 @@ } case _RECORD_TOS: { + JitOptRef tos; + tos = stack_pointer[-1]; + sym_set_recorded_value(tos, (PyObject *)this_instr->operand0); break; } case _RECORD_TOS_TYPE: { + JitOptRef tos; + tos = stack_pointer[-1]; + PyTypeObject *tp = (PyTypeObject *)this_instr->operand0; + sym_set_recorded_type(tos, tp); break; } case _RECORD_NOS: { + JitOptRef nos; + nos = stack_pointer[-2]; + sym_set_recorded_value(nos, (PyObject *)this_instr->operand0); + break; + } + + case _RECORD_NOS_GEN_FUNC: { + JitOptRef nos; + nos = stack_pointer[-2]; + PyFunctionObject *func = (PyFunctionObject *)this_instr->operand0; + assert(func == NULL || PyFunction_Check(func)); + sym_set_recorded_gen_func(nos, func); break; } case _RECORD_4OS: { + JitOptRef value; + value = stack_pointer[-4]; + sym_set_recorded_value(value, (PyObject *)this_instr->operand0); break; } case _RECORD_CALLABLE: { + JitOptRef func; + func = stack_pointer[-2 - oparg]; + sym_set_recorded_value(func, (PyObject *)this_instr->operand0); break; } @@ -4207,7 +4207,7 @@ break; } - case _RECORD_CALLER_CODE: { + case _RECORD_CODE: { break; } diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index bdf1b860d4e789..635ce622c3c589 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -4,6 +4,7 @@ #include "pycore_code.h" #include "pycore_frame.h" +#include "pycore_interpframe.h" #include "pycore_long.h" #include "pycore_optimizer.h" #include "pycore_stats.h" @@ -25,26 +26,26 @@ state represents no information, and the BOTTOM state represents contradictory information. Though symbols logically progress through all intermediate nodes, we often skip in-between states for convenience: - UNKNOWN-------------------+ - | | | -NULL | | -| | | <- Anything below this level is an object. -| NON_NULL-+ | -| | | | <- Anything below this level has a known type version. -| TYPE_VERSION | | -| | | | <- Anything below this level has a known type. -| KNOWN_CLASS | | -| | | | | | PREDICATE -| | | INT* | | | -| | | | | | | <- Anything below this level has a known truthiness. -| | | | | TRUTHINESS | -| | | | | | | -| TUPLE | | | | | -| | | | | | | <- Anything below this level is a known constant. -| KNOWN_VALUE--+----------+ -| | <- Anything below this level is unreachable. + UNKNOWN-------------------+------+ + | | | | +NULL | | RECORDED_VALUE* +| | | | <- Anything below this level is an object. +| NON_NULL-+ | | +| | | | | <- Anything below this level has a known type version. +| TYPE_VERSION | | | +| | | | | <- Anything below this level has a known type. +| KNOWN_CLASS | | | +| | | | | | PREDICATE RECORDED_VALUE(known type) +| | | INT* | | | | +| | | | | | | | <- Anything below this level has a known truthiness. +| TUPLE | | | TRUTHINESS | | +| | | | | | | | <- Anything below this level is a known constant. +| KNOWN_VALUE--+----------+------+ +| | <- Anything below this level is unreachable. BOTTOM + + For example, after guarding that the type of an UNKNOWN local is int, we can narrow the symbol to KNOWN_CLASS (logically progressing though NON_NULL and TYPE_VERSION to get there). Later, we may learn that it is falsey based on the @@ -54,6 +55,7 @@ the same symbol, that would be a contradiction, and the symbol would be set to BOTTOM (indicating that the code is unreachable). INT* is a limited range int, currently a "compact" int. +RECORDED_VALUE* includes RECORDED_TYPE and RECORDED_GEN_FUNC */ @@ -81,7 +83,8 @@ _PyUOpSymPrint(JitOptRef ref) return; } JitOptSymbol *sym = PyJitRef_Unwrap(ref); - switch (sym->tag) { + JitSymType tag = sym->tag; + switch (tag) { case JIT_SYM_UNKNOWN_TAG: printf("", (void *)sym); break; @@ -116,8 +119,17 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_PREDICATE_TAG: printf("", (void *)sym); break; + case JIT_SYM_RECORDED_VALUE_TAG: + printf("", sym->recorded_value.value); + break; + case JIT_SYM_RECORDED_TYPE_TAG: + printf("", sym->recorded_type.type->tp_name); + break; + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + printf("", (void *)sym); + break; default: - printf("", sym->tag, (void *)sym); + printf("", tag, (void *)sym); break; } } @@ -304,8 +316,31 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ) sym_set_bottom(ctx, sym); } return; + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + if (typ != &PyGen_Type) { + sym_set_bottom(ctx, sym); + } + return; case JIT_SYM_BOTTOM_TAG: return; + case JIT_SYM_RECORDED_VALUE_TAG: + if (Py_TYPE(sym->recorded_value.value) == typ) { + sym->recorded_value.known_type = true; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_RECORDED_TYPE_TAG: + if (sym->recorded_type.type == typ) { + sym->tag = JIT_SYM_KNOWN_CLASS_TAG; + sym->cls.version = 0; + sym->cls.type = typ; + } + else { + sym_set_bottom(ctx, sym); + } + return; case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: sym->tag = JIT_SYM_KNOWN_CLASS_TAG; @@ -361,6 +396,12 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver return false; }; return true; + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + if (PyGen_Type.tp_version_tag != version) { + sym_set_bottom(ctx, sym); + return false; + } + return true; case JIT_SYM_TYPE_VERSION_TAG: if (sym->version.version != version) { sym_set_bottom(ctx, sym); @@ -387,6 +428,29 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver return false; } return true; + case JIT_SYM_RECORDED_VALUE_TAG: + if (Py_TYPE(sym->recorded_value.value)->tp_version_tag == version) { + sym->recorded_value.known_type = true; + sym->tag = JIT_SYM_KNOWN_CLASS_TAG; + sym->cls.type = Py_TYPE(sym->recorded_value.value); + sym->cls.version = version; + return true; + } + else { + sym_set_bottom(ctx, sym); + return false; + } + case JIT_SYM_RECORDED_TYPE_TAG: + if (sym->recorded_type.type->tp_version_tag == version) { + sym->tag = JIT_SYM_KNOWN_CLASS_TAG; + sym->cls.type = sym->recorded_type.type; + sym->cls.version = version; + return true; + } + else { + sym_set_bottom(ctx, sym); + return false; + } } Py_UNREACHABLE(); } @@ -398,6 +462,7 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val) JitSymType tag = sym->tag; switch(tag) { case JIT_SYM_NULL_TAG: + case JIT_SYM_RECORDED_GEN_FUNC_TAG: sym_set_bottom(ctx, sym); return; case JIT_SYM_KNOWN_CLASS_TAG: @@ -437,6 +502,11 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val) return; case JIT_SYM_BOTTOM_TAG: return; + case JIT_SYM_RECORDED_VALUE_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: + /* The given value might contradict the recorded one, + * in which case we could return bottom. + * Just discard the recorded value for now */ case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: make_const(sym, const_val); @@ -592,6 +662,12 @@ _Py_uop_sym_get_type(JitOptRef ref) case JIT_SYM_BOTTOM_TAG: case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: + return NULL; + case JIT_SYM_RECORDED_VALUE_TAG: + if (sym->recorded_value.known_type) { + return Py_TYPE(sym->recorded_value.value); + } return NULL; case JIT_SYM_KNOWN_CLASS_TAG: return sym->cls.type; @@ -606,7 +682,8 @@ _Py_uop_sym_get_type(JitOptRef ref) return &PyBool_Type; case JIT_SYM_COMPACT_INT: return &PyLong_Type; - + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + return &PyGen_Type; } Py_UNREACHABLE(); } @@ -621,6 +698,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref) case JIT_SYM_BOTTOM_TAG: case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: + case JIT_SYM_RECORDED_VALUE_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: return 0; case JIT_SYM_TYPE_VERSION_TAG: return sym->version.version; @@ -635,6 +714,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref) return PyBool_Type.tp_version_tag; case JIT_SYM_COMPACT_INT: return PyLong_Type.tp_version_tag; + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + return PyGen_Type.tp_version_tag; } Py_UNREACHABLE(); } @@ -658,11 +739,69 @@ _Py_uop_sym_matches_type_version(JitOptRef sym, unsigned int version) return _Py_uop_sym_get_type_version(sym) == version; } +PyObject * +_Py_uop_sym_get_probable_value(JitOptRef ref) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + JitSymType tag = sym->tag; + switch(tag) { + case JIT_SYM_NULL_TAG: + case JIT_SYM_BOTTOM_TAG: + case JIT_SYM_NON_NULL_TAG: + case JIT_SYM_UNKNOWN_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: + case JIT_SYM_TYPE_VERSION_TAG: + case JIT_SYM_TUPLE_TAG: + case JIT_SYM_PREDICATE_TAG: + case JIT_SYM_TRUTHINESS_TAG: + case JIT_SYM_COMPACT_INT: + case JIT_SYM_KNOWN_CLASS_TAG: + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + return NULL; + case JIT_SYM_RECORDED_VALUE_TAG: + return sym->recorded_value.value; + case JIT_SYM_KNOWN_VALUE_TAG: + return sym->value.value; + } + Py_UNREACHABLE(); +} + +PyCodeObject * +_Py_uop_sym_get_probable_func_code(JitOptRef ref) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + if (sym->tag == JIT_SYM_RECORDED_GEN_FUNC_TAG) { + return (PyCodeObject *)PyFunction_GET_CODE(sym->recorded_gen_func.func); + } + PyObject *obj = _Py_uop_sym_get_probable_value(ref); + if (obj != NULL) { + if (PyFunction_Check(obj)) { + return (PyCodeObject *)PyFunction_GET_CODE(obj); + } + } + return NULL; +} + +PyFunctionObject * +_Py_uop_sym_get_probable_function(JitOptRef ref) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + if (sym->tag == JIT_SYM_RECORDED_GEN_FUNC_TAG) { + return sym->recorded_gen_func.func; + } + PyObject *obj = _Py_uop_sym_get_probable_value(ref); + if (obj != NULL && PyFunction_Check(obj)) { + return (PyFunctionObject *)obj; + } + return NULL; +} + int _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) { JitOptSymbol *sym = PyJitRef_Unwrap(ref); - switch(sym->tag) { + JitSymType tag = sym->tag; + switch (tag) { case JIT_SYM_NULL_TAG: case JIT_SYM_TYPE_VERSION_TAG: case JIT_SYM_BOTTOM_TAG: @@ -670,6 +809,9 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_UNKNOWN_TAG: case JIT_SYM_COMPACT_INT: case JIT_SYM_PREDICATE_TAG: + case JIT_SYM_RECORDED_VALUE_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: + case JIT_SYM_RECORDED_GEN_FUNC_TAG: return -1; case JIT_SYM_KNOWN_CLASS_TAG: /* TODO : @@ -681,7 +823,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_TUPLE_TAG: return sym->tuple.length != 0; case JIT_SYM_TRUTHINESS_TAG: - ; + { JitOptSymbol *value = allocation_base(ctx) + sym->truthiness.value; int truthiness = _Py_uop_sym_truthiness(ctx, PyJitRef_Wrap(value)); @@ -691,6 +833,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) truthiness ^= sym->truthiness.invert; make_const(sym, truthiness ? Py_True : Py_False); return truthiness; + } } PyObject *value = sym->value.value; /* Only handle a few known safe types */ @@ -801,6 +944,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) JitSymType tag = sym->tag; switch(tag) { case JIT_SYM_NULL_TAG: + case JIT_SYM_RECORDED_GEN_FUNC_TAG: sym_set_bottom(ctx, sym); return; case JIT_SYM_KNOWN_CLASS_TAG: @@ -832,6 +976,11 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_BOTTOM_TAG: case JIT_SYM_COMPACT_INT: return; + case JIT_SYM_RECORDED_VALUE_TAG: + case JIT_SYM_RECORDED_TYPE_TAG: + /* The given value might contradict the recorded one, + * in which case we could return bottom. + * Just discard the recorded value for now */ case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: sym->tag = JIT_SYM_COMPACT_INT; @@ -941,6 +1090,222 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx) return PyJitRef_Wrap(sym); } +void +_Py_uop_sym_set_recorded_value(JitOptContext *ctx, JitOptRef ref, PyObject *value) +{ + // It is possible for value to be NULL due to respecialization + // during execution of the traced instruction. + if (value == NULL) { + return; + } + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + JitSymType tag = sym->tag; + switch(tag) { + case JIT_SYM_NULL_TAG: + sym_set_bottom(ctx, sym); + return; + case JIT_SYM_BOTTOM_TAG: + return; + case JIT_SYM_NON_NULL_TAG: + case JIT_SYM_UNKNOWN_TAG: + sym->tag = JIT_SYM_RECORDED_VALUE_TAG; + sym->recorded_value.known_type = false; + sym->recorded_value.value = value; + return; + case JIT_SYM_RECORDED_VALUE_TAG: + if (sym->recorded_value.value != value) { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_RECORDED_TYPE_TAG: + if (sym->recorded_type.type == Py_TYPE(value)) { + sym->tag = JIT_SYM_RECORDED_VALUE_TAG; + sym->recorded_value.known_type = false; + sym->recorded_value.value = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_KNOWN_CLASS_TAG: + if (sym->cls.type == Py_TYPE(value)) { + sym->tag = JIT_SYM_RECORDED_VALUE_TAG; + sym->recorded_value.known_type = true; + sym->recorded_value.value = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_KNOWN_VALUE_TAG: + return; + case JIT_SYM_TYPE_VERSION_TAG: + if (sym->version.version == Py_TYPE(value)->tp_version_tag) { + sym->tag = JIT_SYM_RECORDED_VALUE_TAG; + sym->recorded_value.known_type = true; + sym->recorded_value.value = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + // In these cases the original information is more valuable + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + case JIT_SYM_TUPLE_TAG: + case JIT_SYM_PREDICATE_TAG: + case JIT_SYM_TRUTHINESS_TAG: + case JIT_SYM_COMPACT_INT: + return; + } + Py_UNREACHABLE(); +} +void +_Py_uop_sym_set_recorded_gen_func(JitOptContext *ctx, JitOptRef ref, PyFunctionObject *value) +{ + // It is possible for value to be NULL due to respecialization + // during execution of the traced instruction. + if (value == NULL) { + return; + } + assert(!PyJitRef_IsNull(ref)); + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + JitSymType tag = sym->tag; + switch(tag) { + case JIT_SYM_NULL_TAG: + case JIT_SYM_RECORDED_VALUE_TAG: + case JIT_SYM_KNOWN_VALUE_TAG: + case JIT_SYM_TUPLE_TAG: + case JIT_SYM_PREDICATE_TAG: + case JIT_SYM_TRUTHINESS_TAG: + case JIT_SYM_COMPACT_INT: + sym_set_bottom(ctx, sym); + return; + case JIT_SYM_BOTTOM_TAG: + return; + case JIT_SYM_NON_NULL_TAG: + case JIT_SYM_UNKNOWN_TAG: + sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG; + sym->recorded_gen_func.func = value; + return; + case JIT_SYM_RECORDED_TYPE_TAG: + if (sym->recorded_type.type == &PyGen_Type) { + sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG; + sym->recorded_gen_func.func = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_KNOWN_CLASS_TAG: + if (sym->cls.type == &PyGen_Type) { + sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG; + sym->recorded_gen_func.func = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_TYPE_VERSION_TAG: + if (sym->version.version == PyGen_Type.tp_version_tag) { + sym->tag = JIT_SYM_RECORDED_GEN_FUNC_TAG; + sym->recorded_gen_func.func = value; + } + else { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + if (sym->recorded_gen_func.func != value) { + sym_set_bottom(ctx, sym); + } + return; + } + Py_UNREACHABLE(); +} + +void +_Py_uop_sym_set_recorded_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *type) +{ + // It is possible for type to be NULL due to respecialization + // during execution of the traced instruction. + if (type == NULL) { + return; + } + assert(PyType_Check((PyObject *)type)); + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + JitSymType tag = sym->tag; + switch(tag) { + case JIT_SYM_NULL_TAG: + sym_set_bottom(ctx, sym); + return; + case JIT_SYM_BOTTOM_TAG: + return; + case JIT_SYM_NON_NULL_TAG: + case JIT_SYM_UNKNOWN_TAG: + sym->tag = JIT_SYM_RECORDED_TYPE_TAG; + sym->recorded_type.type = type; + return; + case JIT_SYM_RECORDED_VALUE_TAG: + if (Py_TYPE(sym->recorded_value.value) != type) { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_RECORDED_TYPE_TAG: + if (sym->recorded_type.type != type) { + sym_set_bottom(ctx, sym); + } + return; + case JIT_SYM_KNOWN_CLASS_TAG: + return; + case JIT_SYM_KNOWN_VALUE_TAG: + return; + case JIT_SYM_TYPE_VERSION_TAG: + if (sym->version.version == type->tp_version_tag) { + sym->tag = JIT_SYM_KNOWN_CLASS_TAG; + sym->cls.type = type; + } + else { + sym_set_bottom(ctx, sym); + } + return; + // In these cases the original information is more valuable + case JIT_SYM_TUPLE_TAG: + case JIT_SYM_PREDICATE_TAG: + case JIT_SYM_TRUTHINESS_TAG: + case JIT_SYM_COMPACT_INT: + case JIT_SYM_RECORDED_GEN_FUNC_TAG: + return; + } + Py_UNREACHABLE(); +} + +// 0 on success, -1 on error. +_Py_UOpsAbstractFrame * +_Py_uop_frame_new_from_symbol( + JitOptContext *ctx, + JitOptRef callable, + int curr_stackentries, + JitOptRef *args, + int arg_len) +{ + PyCodeObject *co = _Py_uop_sym_get_probable_func_code(callable); + if (co == NULL) { + ctx->done = true; + return NULL; + } + _Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, co, curr_stackentries, args, arg_len); + if (frame == NULL) { + return NULL; + } + PyFunctionObject *func = _Py_uop_sym_get_probable_function(callable); + if (func != NULL) { + assert(PyFunction_Check(func)); + frame->func = func; + } + assert(frame->stack_pointer != NULL); + return frame; +} + // 0 on success, -1 on error. _Py_UOpsAbstractFrame * _Py_uop_frame_new( @@ -950,6 +1315,7 @@ _Py_uop_frame_new( JitOptRef *args, int arg_len) { + assert(co != NULL); if (ctx->curr_frame_depth >= MAX_ABSTRACT_FRAME_DEPTH) { ctx->done = true; ctx->out_of_space = true; @@ -988,13 +1354,13 @@ _Py_uop_frame_new( frame->locals[i] = local; } - // Initialize the stack as well for (int i = 0; i < curr_stackentries; i++) { JitOptRef stackvar = _Py_uop_sym_new_unknown(ctx); frame->stack[i] = stackvar; } + assert(frame->locals != NULL); return frame; } @@ -1052,6 +1418,7 @@ _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries) if (ctx->curr_frame_depth >= 1) { ctx->frame = &ctx->frames[ctx->curr_frame_depth - 1]; + assert(ctx->frame->locals != NULL); // We returned to the correct code. Nothing to do here. if (co == ctx->frame->code) { @@ -1079,6 +1446,7 @@ _Py_uop_frame_pop(JitOptContext *ctx, PyCodeObject *co, int curr_stackentries) ctx->curr_frame_depth++; ctx->frame = new_frame; + assert(ctx->frame->locals != NULL); return 0; } @@ -1111,6 +1479,7 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) PyObject *val_43 = NULL; PyObject *val_big = NULL; PyObject *tuple = NULL; + PyFunctionObject *func = NULL; // Use a single 'sym' variable so copy-pasting tests is easier. JitOptRef ref = _Py_uop_sym_new_unknown(ctx); @@ -1521,11 +1890,118 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_matches_type(ref_int, &PyLong_Type), "43 is not an int"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref_int) == val_43, "43 isn't 43"); + // Test recorded values + + /* Test that recorded values aren't treated as known values*/ + JitOptRef rv1 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_value(ctx, rv1, val_42); + TEST_PREDICATE(!_Py_uop_sym_matches_type(rv1, &PyLong_Type), "recorded value is treated as known"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv1) == NULL, "recorded value is treated as known"); + TEST_PREDICATE(!_Py_uop_sym_is_compact_int(rv1), "recorded value is treated as known"); + + /* Test that setting type or value narrows correctly */ + JitOptRef rv2 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_value(ctx, rv2, val_42); + _Py_uop_sym_set_const(ctx, rv2, val_42); + TEST_PREDICATE(_Py_uop_sym_matches_type(rv2, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv2) == val_42, "recorded value doesn't narrow"); + + JitOptRef rv3 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_value(ctx, rv3, val_42); + _Py_uop_sym_set_type(ctx, rv3, &PyLong_Type); + TEST_PREDICATE(_Py_uop_sym_matches_type(rv3, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv3) == NULL, "recorded value with type is treated as known"); + + JitOptRef rv4 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_value(ctx, rv4, val_42); + _Py_uop_sym_set_type_version(ctx, rv4, PyLong_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_matches_type(rv4, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rv4) == NULL, "recorded value with type is treated as known"); + + // test recorded types + + /* Test that recorded type aren't treated as known values*/ + JitOptRef rt1 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_type(ctx, rt1, &PyLong_Type); + TEST_PREDICATE(!_Py_uop_sym_matches_type(rt1, &PyLong_Type), "recorded type is treated as known"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt1) == NULL, "recorded type is treated as known value"); + + /* Test that setting type or value narrows correctly */ + JitOptRef rt2 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_type(ctx, rt2, &PyLong_Type); + _Py_uop_sym_set_const(ctx, rt2, val_42); + TEST_PREDICATE(_Py_uop_sym_matches_type(rt2, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt2) == val_42, "recorded value doesn't narrow"); + + JitOptRef rt3 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_type(ctx, rt3, &PyLong_Type); + _Py_uop_sym_set_type(ctx, rt3, &PyLong_Type); + TEST_PREDICATE(_Py_uop_sym_matches_type(rt3, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt3) == NULL, "known type is treated as known value"); + + JitOptRef rt4 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_type(ctx, rt4, &PyLong_Type); + _Py_uop_sym_set_type_version(ctx, rt4, PyLong_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_matches_type(rt4, &PyLong_Type), "recorded value doesn't narrow"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rt4) == NULL, "recorded value with type is treated as known"); + + // test recorded gen function + + PyObject *dict = PyDict_New(); + if (dict == NULL) { + goto fail; + } + PyCodeObject *code = PyCode_NewEmpty(__FILE__, "uop_symbols_test", __LINE__); + if (code == NULL) { + goto fail; + } + func = (PyFunctionObject *)PyFunction_New((PyObject *)code, dict); + if (func == NULL) { + goto fail; + } + + /* Test that recorded type aren't treated as known values*/ + JitOptRef rg1 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_gen_func(ctx, rg1, func); + TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg1) == NULL, "recorded gen func is treated as known value"); + + /* Test that setting type narrows correctly */ + + JitOptRef rg2 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_gen_func(ctx, rg2, func); + _Py_uop_sym_set_type(ctx, rg2, &PyGen_Type); + TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg2) == NULL, "known type is treated as known value"); + + JitOptRef rg3 = _Py_uop_sym_new_unknown(ctx); + _Py_uop_sym_set_recorded_gen_func(ctx, rg3, func); + _Py_uop_sym_set_type_version(ctx, rg3, PyGen_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_matches_type(rg1, &PyGen_Type), "recorded gen func not treated as generator"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, rg3) == NULL, "recorded value with type is treated as known"); + + /* Test contradictions */ + _Py_uop_sym_set_type(ctx, rv1, &PyFloat_Type); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rv1), "recorded value cast to other type isn't bottom"); + _Py_uop_sym_set_type_version(ctx, rv2, PyFloat_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rv2), "recorded value cast to other type version isn't bottom"); + + _Py_uop_sym_set_type(ctx, rt1, &PyFloat_Type); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rv1), "recorded type cast to other type isn't bottom"); + _Py_uop_sym_set_type_version(ctx, rt2, PyFloat_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rv2), "recorded type cast to other type version isn't bottom"); + + _Py_uop_sym_set_type(ctx, rg1, &PyFloat_Type); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rg1), "recorded gen func cast to other type isn't bottom"); + _Py_uop_sym_set_type_version(ctx, rg2, PyFloat_Type.tp_version_tag); + TEST_PREDICATE(_Py_uop_sym_is_bottom(rg2), "recorded gen func cast to other type version isn't bottom"); + _Py_uop_abstractcontext_fini(ctx); Py_DECREF(val_42); Py_DECREF(val_43); Py_DECREF(val_big); Py_DECREF(tuple); + Py_DECREF(func); Py_RETURN_NONE; fail: @@ -1533,7 +2009,8 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) Py_XDECREF(val_42); Py_XDECREF(val_43); Py_XDECREF(val_big); - Py_DECREF(tuple); + Py_XDECREF(tuple); + Py_XDECREF(func); return NULL; } diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h index ba85ed752d2c96..c6709f9a9d6bec 100644 --- a/Python/record_functions.c.h +++ b/Python/record_functions.c.h @@ -27,6 +27,19 @@ void _PyOpcode_RecordFunction_NOS(_PyInterpreterFrame *frame, _PyStackRef *stack Py_INCREF(*recorded_value); } +void _PyOpcode_RecordFunction_NOS_GEN_FUNC(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef nos; + nos = stack_pointer[-2]; + PyObject *obj = PyStackRef_AsPyObjectBorrow(nos); + if (PyGen_Check(obj)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *func = (PyObject *)_PyFrame_GetFunction(&((PyGenObject *)obj)->gi_iframe); + stack_pointer = _PyFrame_GetStackPointer(frame); + *recorded_value = (PyObject *)func; + Py_INCREF(*recorded_value); + } +} + void _PyOpcode_RecordFunction_4OS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { _PyStackRef value; value = stack_pointer[-4]; @@ -52,27 +65,21 @@ void _PyOpcode_RecordFunction_BOUND_METHOD(_PyInterpreterFrame *frame, _PyStackR } } -void _PyOpcode_RecordFunction_CALLER_CODE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { - _PyInterpreterFrame *caller_frame = frame->previous; - if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) { - PyCodeObject *code = _PyFrame_GetCode(frame->previous); - *recorded_value = (PyObject *)code; - Py_INCREF(*recorded_value); - } +void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + *recorded_value = (PyObject *)NULL; + Py_INCREF(*recorded_value); } #define _RECORD_TOS_TYPE_INDEX 1 -#define _RECORD_TOS_INDEX 2 -#define _RECORD_CALLER_CODE_INDEX 3 -#define _RECORD_NOS_INDEX 4 -#define _RECORD_CALLABLE_INDEX 5 -#define _RECORD_BOUND_METHOD_INDEX 6 -#define _RECORD_4OS_INDEX 7 +#define _RECORD_NOS_INDEX 2 +#define _RECORD_NOS_GEN_FUNC_INDEX 3 +#define _RECORD_CALLABLE_INDEX 4 +#define _RECORD_BOUND_METHOD_INDEX 5 +#define _RECORD_4OS_INDEX 6 const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [TO_BOOL_ALWAYS_TRUE] = _RECORD_TOS_TYPE_INDEX, - [BINARY_OP_SUBSCR_GETITEM] = _RECORD_TOS_INDEX, - [RETURN_VALUE] = _RECORD_CALLER_CODE_INDEX, - [YIELD_VALUE] = _RECORD_CALLER_CODE_INDEX, + [BINARY_OP_SUBSCR_GETITEM] = _RECORD_NOS_INDEX, + [SEND_GEN] = _RECORD_NOS_GEN_FUNC_INDEX, [LOAD_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX, @@ -80,7 +87,7 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [LOAD_ATTR_PROPERTY] = _RECORD_TOS_TYPE_INDEX, [STORE_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX, [STORE_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX, - [FOR_ITER_GEN] = _RECORD_NOS_INDEX, + [FOR_ITER_GEN] = _RECORD_NOS_GEN_FUNC_INDEX, [LOAD_ATTR_METHOD_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_METHOD_NO_DICT] = _RECORD_TOS_TYPE_INDEX, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX, @@ -100,15 +107,13 @@ const uint8_t _PyOpcode_RecordFunctionIndices[256] = { [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _RECORD_CALLABLE_INDEX, [CALL_METHOD_DESCRIPTOR_NOARGS] = _RECORD_CALLABLE_INDEX, [CALL_EX_PY] = _RECORD_4OS_INDEX, - [RETURN_GENERATOR] = _RECORD_CALLER_CODE_INDEX, }; -const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[8] = { +const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[7] = { [0] = NULL, [_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE, - [_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS, - [_RECORD_CALLER_CODE_INDEX] = _PyOpcode_RecordFunction_CALLER_CODE, [_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS, + [_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC, [_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE, [_RECORD_BOUND_METHOD_INDEX] = _PyOpcode_RecordFunction_BOUND_METHOD, [_RECORD_4OS_INDEX] = _PyOpcode_RecordFunction_4OS, From e6b8fcc17a7c6ab0b089268169bf01f4161db5c4 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 5 Feb 2026 11:32:56 +0100 Subject: [PATCH 11/13] gh-144330: Initialize classmethod and staticmethod in new (#144469) Move classmethod and staticmethod initialization from __init__() to __new__(). PyClassMethod_New() and PyStaticMethod_New() now copy attributes of the wrapped functions: __module__, __name__, __qualname__ and __doc__. Change static type initialization: initialize PyStaticMethod_Type and PyCFunction_Type earlier. Remove test_refleaks_in_classmethod___init__() and test_refleaks_in_staticmethod___init__() tests from test_descr since classmethod and staticmethod have no __init__() method anymore. --- Lib/test/test_descr.py | 32 ++--- ...-02-04-11-19-45.gh-issue-144330.kOowSb.rst | 2 + Objects/funcobject.c | 130 +++++++++++++----- Objects/object.c | 7 +- 4 files changed, 116 insertions(+), 55 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-02-04-11-19-45.gh-issue-144330.kOowSb.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 0dc61ca7fb0da3..d6e3719479a214 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1727,6 +1727,18 @@ def annotated(cls) -> int: pass del method.__annotate__ self.assertIs(method.__annotate__, original_annotate) + def test_classmethod_without_dict_access(self): + class Spam: + @classmethod + def method(cls, x, y): + pass + + obj = Spam.__dict__['method'] + self.assertIsInstance(obj, classmethod) + self.assertEqual(obj.__annotations__, {}) + self.assertEqual(obj.__name__, 'method') + self.assertEqual(obj.__module__, __name__) + def test_staticmethod_annotations_without_dict_access(self): # gh-125017: this used to crash class Spam: @@ -1737,15 +1749,8 @@ def __new__(cls, x, y): obj = Spam.__dict__['__new__'] self.assertIsInstance(obj, staticmethod) self.assertEqual(obj.__annotations__, {}) - - @support.refcount_test - def test_refleaks_in_classmethod___init__(self): - gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') - cm = classmethod(None) - refs_before = gettotalrefcount() - for i in range(100): - cm.__init__(None) - self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) + self.assertEqual(obj.__name__, '__new__') + self.assertEqual(obj.__module__, __name__) @support.impl_detail("the module 'xxsubtype' is internal") @unittest.skipIf(xxsubtype is None, "requires xxsubtype module") @@ -1822,15 +1827,6 @@ class D(C): del sm.x self.assertNotHasAttr(sm, "x") - @support.refcount_test - def test_refleaks_in_staticmethod___init__(self): - gettotalrefcount = support.get_attribute(sys, 'gettotalrefcount') - sm = staticmethod(None) - refs_before = gettotalrefcount() - for i in range(100): - sm.__init__(None) - self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) - @support.impl_detail("the module 'xxsubtype' is internal") @unittest.skipIf(xxsubtype is None, "requires xxsubtype module") def test_staticmethods_in_c(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-02-04-11-19-45.gh-issue-144330.kOowSb.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-04-11-19-45.gh-issue-144330.kOowSb.rst new file mode 100644 index 00000000000000..b3c61e162f4ffb --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-02-04-11-19-45.gh-issue-144330.kOowSb.rst @@ -0,0 +1,2 @@ +Move ``classmethod`` and ``staticmethod`` initialization from ``__init__()`` +to ``__new__()``. Patch by Victor Stinner. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index b659ac8023373b..2bf21fa045e3f1 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1466,33 +1466,59 @@ static PyObject * cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) { classmethod *cm = (classmethod *)self; - - if (cm->cm_callable == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "uninitialized classmethod object"); - return NULL; - } if (type == NULL) type = (PyObject *)(Py_TYPE(obj)); return PyMethod_New(cm->cm_callable, type); } static int -cm_init(PyObject *self, PyObject *args, PyObject *kwds) +cm_set_callable(classmethod *cm, PyObject *callable) { - classmethod *cm = (classmethod *)self; - PyObject *callable; + assert(callable != NULL); + if (cm->cm_callable == callable) { + // cm_init() sets the same callable than cm_new() + return 0; + } - if (!_PyArg_NoKeywords("classmethod", kwds)) - return -1; - if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) - return -1; Py_XSETREF(cm->cm_callable, Py_NewRef(callable)); + return functools_wraps((PyObject *)cm, cm->cm_callable); +} + +static PyObject * +cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if (!_PyArg_NoKeywords("classmethod", kwds)) { + return NULL; + } + PyObject *callable; // borrowed ref + if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) { + return NULL; + } - if (functools_wraps((PyObject *)cm, cm->cm_callable) < 0) { + classmethod *cm = (classmethod *)PyType_GenericAlloc(type, 0); + if (cm == NULL) { + return NULL; + } + if (cm_set_callable(cm, callable) < 0) { + Py_DECREF(cm); + return NULL; + } + return (PyObject *)cm; +} + +static int +cm_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + if (!_PyArg_NoKeywords("classmethod", kwds)) { return -1; } - return 0; + PyObject *callable; // borrowed ref + if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) { + return -1; + } + + classmethod *cm = (classmethod *)self; + return cm_set_callable(cm, callable); } static PyMemberDef cm_memberlist[] = { @@ -1623,7 +1649,7 @@ PyTypeObject PyClassMethod_Type = { offsetof(classmethod, cm_dict), /* tp_dictoffset */ cm_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + cm_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; @@ -1632,8 +1658,12 @@ PyClassMethod_New(PyObject *callable) { classmethod *cm = (classmethod *) PyType_GenericAlloc(&PyClassMethod_Type, 0); - if (cm != NULL) { - cm->cm_callable = Py_NewRef(callable); + if (cm == NULL) { + return NULL; + } + if (cm_set_callable(cm, callable) < 0) { + Py_DECREF(cm); + return NULL; } return (PyObject *)cm; } @@ -1699,31 +1729,57 @@ static PyObject * sm_descr_get(PyObject *self, PyObject *obj, PyObject *type) { staticmethod *sm = (staticmethod *)self; + return Py_NewRef(sm->sm_callable); +} - if (sm->sm_callable == NULL) { - PyErr_SetString(PyExc_RuntimeError, - "uninitialized staticmethod object"); +static int +sm_set_callable(staticmethod *sm, PyObject *callable) +{ + assert(callable != NULL); + if (sm->sm_callable == callable) { + // sm_init() sets the same callable than sm_new() + return 0; + } + + Py_XSETREF(sm->sm_callable, Py_NewRef(callable)); + return functools_wraps((PyObject *)sm, sm->sm_callable); +} + +static PyObject * +sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if (!_PyArg_NoKeywords("staticmethod", kwds)) { return NULL; } - return Py_NewRef(sm->sm_callable); + PyObject *callable; // borrowed ref + if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) { + return NULL; + } + + staticmethod *sm = (staticmethod *)PyType_GenericAlloc(type, 0); + if (sm == NULL) { + return NULL; + } + if (sm_set_callable(sm, callable) < 0) { + Py_DECREF(sm); + return NULL; + } + return (PyObject *)sm; } static int sm_init(PyObject *self, PyObject *args, PyObject *kwds) { - staticmethod *sm = (staticmethod *)self; - PyObject *callable; - - if (!_PyArg_NoKeywords("staticmethod", kwds)) + if (!_PyArg_NoKeywords("staticmethod", kwds)) { return -1; - if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) - return -1; - Py_XSETREF(sm->sm_callable, Py_NewRef(callable)); - - if (functools_wraps((PyObject *)sm, sm->sm_callable) < 0) { + } + PyObject *callable; // borrowed ref + if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) { return -1; } - return 0; + + staticmethod *sm = (staticmethod *)self; + return sm_set_callable(sm, callable); } static PyObject* @@ -1858,7 +1914,7 @@ PyTypeObject PyStaticMethod_Type = { offsetof(staticmethod, sm_dict), /* tp_dictoffset */ sm_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + sm_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; @@ -1867,8 +1923,12 @@ PyStaticMethod_New(PyObject *callable) { staticmethod *sm = (staticmethod *) PyType_GenericAlloc(&PyStaticMethod_Type, 0); - if (sm != NULL) { - sm->sm_callable = Py_NewRef(callable); + if (sm == NULL) { + return NULL; + } + if (sm_set_callable(sm, callable) < 0) { + Py_DECREF(sm); + return NULL; } return (PyObject *)sm; } diff --git a/Objects/object.c b/Objects/object.c index 649b109d5cb0bc..38717def24239f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2446,13 +2446,17 @@ static PyTypeObject* static_types[] = { &PyBaseObject_Type, &PyType_Type, + // PyStaticMethod_Type and PyCFunction_Type are used by PyType_Ready() + // on other types and so must be initialized first. + &PyStaticMethod_Type, + &PyCFunction_Type, + // Static types with base=&PyBaseObject_Type &PyAsyncGen_Type, &PyByteArrayIter_Type, &PyByteArray_Type, &PyBytesIter_Type, &PyBytes_Type, - &PyCFunction_Type, &PyCallIter_Type, &PyCapsule_Type, &PyCell_Type, @@ -2509,7 +2513,6 @@ static PyTypeObject* static_types[] = { &PySetIter_Type, &PySet_Type, &PySlice_Type, - &PyStaticMethod_Type, &PyStdPrinter_Type, &PySuper_Type, &PyTraceBack_Type, From aa549fbd23de1e861cb611e1eeb0549f406d73f9 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:58:18 +0000 Subject: [PATCH 12/13] gh-144363: Update bundled libexpat to 2.7.4 (#144365) * Update to 2.7.4 * update expat license copyright year to match and a pedantic #define * include COPYING update in refresh.sh * Update checksum for copying --------- Co-authored-by: Gregory P. Smith Co-authored-by: Petr Viktorin --- ...-01-31-17-15-49.gh-issue-144363.X9f0sU.rst | 1 + Misc/sbom.spdx.json | 40 +++---- Modules/expat/COPYING | 2 +- Modules/expat/expat.h | 4 +- Modules/expat/expat_config.h | 2 +- Modules/expat/expat_external.h | 5 +- Modules/expat/internal.h | 2 +- Modules/expat/refresh.sh | 9 +- Modules/expat/xmlparse.c | 110 ++++++++++-------- Modules/expat/xmlrole.c | 2 +- Modules/expat/xmltok.c | 2 +- Modules/expat/xmltok_ns.c | 5 +- 12 files changed, 98 insertions(+), 86 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-31-17-15-49.gh-issue-144363.X9f0sU.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-31-17-15-49.gh-issue-144363.X9f0sU.rst b/Misc/NEWS.d/next/Library/2026-01-31-17-15-49.gh-issue-144363.X9f0sU.rst new file mode 100644 index 00000000000000..c17cea6613d06b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-31-17-15-49.gh-issue-144363.X9f0sU.rst @@ -0,0 +1 @@ +Update bundled `libexpat `_ to 2.7.4 diff --git a/Misc/sbom.spdx.json b/Misc/sbom.spdx.json index e9554bf78374a6..c79bbd2878271e 100644 --- a/Misc/sbom.spdx.json +++ b/Misc/sbom.spdx.json @@ -6,11 +6,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "39e6f567a10e36b2e77727e98e60bbcb3eb3af0b" + "checksumValue": "f1b1126ed7da8f2068302e7a692b0600e6f94b07" }, { "algorithm": "SHA256", - "checksumValue": "122f2c27000472a201d337b9b31f7eb2b52d091b02857061a8880371612d9534" + "checksumValue": "31b15de82aa19a845156169a17a5488bf597e561b2c318d159ed583139b25e87" } ], "fileName": "Modules/expat/COPYING" @@ -48,11 +48,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "a4395dd0589a97aab0904f7a5f5dc5781a086aa2" + "checksumValue": "9bd33bd279c0d7ea37b0f2d7e07c7c53b7053507" }, { "algorithm": "SHA256", - "checksumValue": "610b844bbfa3ec955772cc825db4d4db470827d57adcb214ad372d0eaf00e591" + "checksumValue": "d20997001462356b5ce3810ebf5256c8205f58462c64f21eb9bf80f8d1822b08" } ], "fileName": "Modules/expat/expat.h" @@ -62,11 +62,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "c22196e3d8bee88fcdda715623b3b9d2119d2fb3" + "checksumValue": "e658ee5d638ab326109282ff09f1541e27fff8c2" }, { "algorithm": "SHA256", - "checksumValue": "f2c2283ba03b057e92beefc7f81ba901ebb6dfc1a45b036c8a7d65808eb77a84" + "checksumValue": "dbe0582b8f8a8140aca97009e8760105ceed9e7df01ea9d8b3fe47cebf2e5b2d" } ], "fileName": "Modules/expat/expat_external.h" @@ -90,11 +90,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "7dce7d98943c5db33ae05e54801dcafb4547b9dd" + "checksumValue": "6a4a232233ba1034c3f2b459159d502e9b2d413b" }, { "algorithm": "SHA256", - "checksumValue": "6bfe307d52e7e4c71dbc30d3bd902a4905cdd83bbe4226a7e8dfa8e4c462a157" + "checksumValue": "c803935722f0dbdeeede7f040028fb119135e96dfad949479f8a5304b885bdd6" } ], "fileName": "Modules/expat/internal.h" @@ -174,11 +174,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "4c81a1f04fc653877c63c834145c18f93cd95f3e" + "checksumValue": "7d3d7d72aa56c53fb5b9e10c0e74e161381f0255" }, { "algorithm": "SHA256", - "checksumValue": "04a379615f476d55f95ca1853107e20627b48ca4afe8d0fd5981ac77188bf0a6" + "checksumValue": "f4f87aa0268d92f2b8f5e663788bfadd2e926477d0b061ed4463c02ad29a3e25" } ], "fileName": "Modules/expat/xmlparse.c" @@ -188,11 +188,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "ef767128d2dda99436712dcf3465dde5dbaab876" + "checksumValue": "c8769fcb93f00272a6e6ca560be633649c817ff7" }, { "algorithm": "SHA256", - "checksumValue": "71fb52aa302cf6f56e41943009965804f49ff2210d9bd15b258f70aaf70db772" + "checksumValue": "5b81f0eb0e144b611dbd1bc9e6037075a16bff94f823d57a81eb2a3e4999e91a" } ], "fileName": "Modules/expat/xmlrole.c" @@ -216,11 +216,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "1e2d35d90a1c269217f83d3bdf3c71cc22cb4c3f" + "checksumValue": "63e4766a09e63760c6518670509198f8d638f4ad" }, { "algorithm": "SHA256", - "checksumValue": "98d0fc735041956cc2e7bbbe2fb8f03130859410e0aee5e8015f406a37c02a3c" + "checksumValue": "0ad3f915f2748dc91bf4e4b4a50cf40bf2c95769d0eca7e3b293a230d82bb779" } ], "fileName": "Modules/expat/xmltok.c" @@ -272,11 +272,11 @@ "checksums": [ { "algorithm": "SHA1", - "checksumValue": "2d82d0a1201f78d478b30d108ff8fc27ee3e2672" + "checksumValue": "41b8c8fc275882c76d4210b7d40a18e506b07147" }, { "algorithm": "SHA256", - "checksumValue": "6ce6d03193279078d55280150fe91e7370370b504a6c123a79182f28341f3e90" + "checksumValue": "b2188c7e5fa5b33e355cf6cf342dfb8f6e23859f2a6b1ddf79841d7f84f7b196" } ], "fileName": "Modules/expat/xmltok_ns.c" @@ -1730,14 +1730,14 @@ "checksums": [ { "algorithm": "SHA256", - "checksumValue": "821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732" + "checksumValue": "461ecc8aa98ab1a68c2db788175665d1a4db640dc05bf0e289b6ea17122144ec" } ], - "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_7_3/expat-2.7.3.tar.gz", + "downloadLocation": "https://github.com/libexpat/libexpat/releases/download/R_2_7_4/expat-2.7.4.tar.gz", "externalRefs": [ { "referenceCategory": "SECURITY", - "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.7.3:*:*:*:*:*:*:*", + "referenceLocator": "cpe:2.3:a:libexpat_project:libexpat:2.7.4:*:*:*:*:*:*:*", "referenceType": "cpe23Type" } ], @@ -1745,7 +1745,7 @@ "name": "expat", "originator": "Organization: Expat development team", "primaryPackagePurpose": "SOURCE", - "versionInfo": "2.7.3" + "versionInfo": "2.7.4" }, { "SPDXID": "SPDXRef-PACKAGE-hacl-star", diff --git a/Modules/expat/COPYING b/Modules/expat/COPYING index ce9e5939291e45..c6d184a8aae845 100644 --- a/Modules/expat/COPYING +++ b/Modules/expat/COPYING @@ -1,5 +1,5 @@ Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper -Copyright (c) 2001-2022 Expat maintainers +Copyright (c) 2001-2025 Expat maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/Modules/expat/expat.h b/Modules/expat/expat.h index 290dfeb0f6dd6a..6c7c4186927725 100644 --- a/Modules/expat/expat.h +++ b/Modules/expat/expat.h @@ -11,7 +11,7 @@ Copyright (c) 2000-2005 Fred L. Drake, Jr. Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2016 Karl Waclawek - Copyright (c) 2016-2025 Sebastian Pipping + Copyright (c) 2016-2026 Sebastian Pipping Copyright (c) 2016 Cristian Rodríguez Copyright (c) 2016 Thomas Beutlich Copyright (c) 2017 Rhodri James @@ -1082,7 +1082,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ # define XML_MAJOR_VERSION 2 # define XML_MINOR_VERSION 7 -# define XML_MICRO_VERSION 3 +# define XML_MICRO_VERSION 4 # ifdef __cplusplus } diff --git a/Modules/expat/expat_config.h b/Modules/expat/expat_config.h index e7d9499d9078d9..09d3161dbc0fb2 100644 --- a/Modules/expat/expat_config.h +++ b/Modules/expat/expat_config.h @@ -3,7 +3,7 @@ * distribution. */ #ifndef EXPAT_CONFIG_H -#define EXPAT_CONFIG_H +#define EXPAT_CONFIG_H 1 #include #ifdef WORDS_BIGENDIAN diff --git a/Modules/expat/expat_external.h b/Modules/expat/expat_external.h index 0f01a05d0e9560..6f3f3c48ce9cff 100644 --- a/Modules/expat/expat_external.h +++ b/Modules/expat/expat_external.h @@ -12,7 +12,7 @@ Copyright (c) 2001-2002 Greg Stein Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2016 Cristian Rodríguez - Copyright (c) 2016-2019 Sebastian Pipping + Copyright (c) 2016-2025 Sebastian Pipping Copyright (c) 2017 Rhodri James Copyright (c) 2018 Yury Gribov Licensed under the MIT license: @@ -91,8 +91,7 @@ # ifndef XML_BUILDING_EXPAT /* using Expat from an application */ -# if defined(_MSC_EXTENSIONS) && ! defined(__BEOS__) \ - && ! defined(__CYGWIN__) +# if defined(_MSC_VER) && ! defined(__BEOS__) && ! defined(__CYGWIN__) # define XMLIMPORT __declspec(dllimport) # endif diff --git a/Modules/expat/internal.h b/Modules/expat/internal.h index 8f5edf48ef7c00..61266ebb7723d1 100644 --- a/Modules/expat/internal.h +++ b/Modules/expat/internal.h @@ -128,7 +128,7 @@ # elif ULONG_MAX == 18446744073709551615u // 2^64-1 # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld" # define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu" -# elif defined(EMSCRIPTEN) // 32bit mode Emscripten +# elif defined(__wasm32__) // 32bit mode Emscripten or WASI SDK # define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld" # define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu" # else diff --git a/Modules/expat/refresh.sh b/Modules/expat/refresh.sh index d1bf5d19afa007..550340467a15a7 100755 --- a/Modules/expat/refresh.sh +++ b/Modules/expat/refresh.sh @@ -12,9 +12,9 @@ fi # Update this when updating to a new version after verifying that the changes # the update brings in are good. These values are used for verifying the SBOM, too. -expected_libexpat_tag="R_2_7_3" -expected_libexpat_version="2.7.3" -expected_libexpat_sha256="821ac9710d2c073eaf13e1b1895a9c9aa66c1157a99635c639fbff65cdbdd732" +expected_libexpat_tag="R_2_7_4" +expected_libexpat_version="2.7.4" +expected_libexpat_sha256="461ecc8aa98ab1a68c2db788175665d1a4db640dc05bf0e289b6ea17122144ec" expat_dir="$(realpath "$(dirname -- "${BASH_SOURCE[0]}")")" cd ${expat_dir} @@ -24,6 +24,9 @@ curl --location "https://github.com/libexpat/libexpat/releases/download/${expect echo "${expected_libexpat_sha256} libexpat.tar.gz" | sha256sum --check # Step 2: Pull files from the libexpat distribution + +tar xzvf libexpat.tar.gz "expat-${expected_libexpat_version}/COPYING" --strip-components 2 + declare -a lib_files lib_files=( ascii.h diff --git a/Modules/expat/xmlparse.c b/Modules/expat/xmlparse.c index a187a3a18f1994..086fca59112ee1 100644 --- a/Modules/expat/xmlparse.c +++ b/Modules/expat/xmlparse.c @@ -1,4 +1,4 @@ -/* 28bcd8b1ba7eb595d82822908257fd9c3589b4243e3c922d0369f35bfcd7b506 (2.7.3+) +/* fab937ab8b186d7d296013669c332e6dfce2f99567882cff1f8eb24223c524a7 (2.7.4+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -13,7 +13,7 @@ Copyright (c) 2002-2016 Karl Waclawek Copyright (c) 2005-2009 Steven Solie Copyright (c) 2016 Eric Rahm - Copyright (c) 2016-2025 Sebastian Pipping + Copyright (c) 2016-2026 Sebastian Pipping Copyright (c) 2016 Gaurav Copyright (c) 2016 Thomas Beutlich Copyright (c) 2016 Gustavo Grieco @@ -42,6 +42,9 @@ Copyright (c) 2024-2025 Berkay Eren Ürün Copyright (c) 2024 Hanno Böck Copyright (c) 2025 Matthew Fernandez + Copyright (c) 2025 Atrem Borovik + Copyright (c) 2025 Alfonso Gregory + Copyright (c) 2026 Rosen Penev Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -101,7 +104,7 @@ #include /* INT_MAX, UINT_MAX */ #include /* fprintf */ #include /* getenv, rand_s */ -#include /* uintptr_t */ +#include /* SIZE_MAX, uintptr_t */ #include /* isnan */ #ifdef _WIN32 @@ -134,11 +137,6 @@ # endif /* defined(GRND_NONBLOCK) */ #endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */ -#if defined(HAVE_LIBBSD) \ - && (defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_ARC4RANDOM)) -# include -#endif - #if defined(_WIN32) && ! defined(LOAD_LIBRARY_SEARCH_SYSTEM32) # define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif @@ -155,8 +153,6 @@ * Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \ * BSD / macOS >=10.7 / glibc >=2.36 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \ * BSD / macOS (including <10.7) / glibc >=2.36 (arc4random): HAVE_ARC4RANDOM, \ - * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \ - * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \ * Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \ * Windows >=Vista (rand_s): _WIN32. \ \ @@ -311,8 +307,11 @@ typedef struct tag { const char *rawName; /* tagName in the original encoding */ int rawNameLength; TAG_NAME name; /* tagName in the API encoding */ - char *buf; /* buffer for name components */ - char *bufEnd; /* end of the buffer */ + union { + char *raw; /* for byte-level access (rawName storage) */ + XML_Char *str; /* for character-level access (converted name) */ + } buf; /* buffer for name components */ + char *bufEnd; /* end of the buffer */ BINDING *bindings; } TAG; @@ -349,7 +348,7 @@ typedef struct { typedef struct block { struct block *next; int size; - XML_Char s[1]; + XML_Char s[]; } BLOCK; typedef struct { @@ -1230,8 +1229,11 @@ generate_hash_secret_salt(XML_Parser parser) { # endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */ /* .. and self-made low quality for backup: */ + entropy = gather_time_entropy(); +# if ! defined(__wasi__) /* Process ID is 0 bits entropy if attacker has local access */ - entropy = gather_time_entropy() ^ getpid(); + entropy ^= getpid(); +# endif /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */ if (sizeof(unsigned long) == 4) { @@ -1754,6 +1756,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, XML_ExternalEntityRefHandler oldExternalEntityRefHandler; XML_SkippedEntityHandler oldSkippedEntityHandler; XML_UnknownEncodingHandler oldUnknownEncodingHandler; + void *oldUnknownEncodingHandlerData; XML_ElementDeclHandler oldElementDeclHandler; XML_AttlistDeclHandler oldAttlistDeclHandler; XML_EntityDeclHandler oldEntityDeclHandler; @@ -1799,6 +1802,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, oldExternalEntityRefHandler = parser->m_externalEntityRefHandler; oldSkippedEntityHandler = parser->m_skippedEntityHandler; oldUnknownEncodingHandler = parser->m_unknownEncodingHandler; + oldUnknownEncodingHandlerData = parser->m_unknownEncodingHandlerData; oldElementDeclHandler = parser->m_elementDeclHandler; oldAttlistDeclHandler = parser->m_attlistDeclHandler; oldEntityDeclHandler = parser->m_entityDeclHandler; @@ -1859,6 +1863,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context, parser->m_externalEntityRefHandler = oldExternalEntityRefHandler; parser->m_skippedEntityHandler = oldSkippedEntityHandler; parser->m_unknownEncodingHandler = oldUnknownEncodingHandler; + parser->m_unknownEncodingHandlerData = oldUnknownEncodingHandlerData; parser->m_elementDeclHandler = oldElementDeclHandler; parser->m_attlistDeclHandler = oldAttlistDeclHandler; parser->m_entityDeclHandler = oldEntityDeclHandler; @@ -1934,7 +1939,7 @@ XML_ParserFree(XML_Parser parser) { } p = tagList; tagList = tagList->parent; - FREE(parser, p->buf); + FREE(parser, p->buf.raw); destroyBindings(p->bindings, parser); FREE(parser, p); } @@ -2599,7 +2604,7 @@ XML_GetBuffer(XML_Parser parser, int len) { // NOTE: We are avoiding MALLOC(..) here to leave limiting // the input size to the application using Expat. newBuf = parser->m_mem.malloc_fcn(bufferSize); - if (newBuf == 0) { + if (newBuf == NULL) { parser->m_errorCode = XML_ERROR_NO_MEMORY; return NULL; } @@ -3126,7 +3131,7 @@ storeRawNames(XML_Parser parser) { size_t bufSize; size_t nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); size_t rawNameLen; - char *rawNameBuf = tag->buf + nameLen; + char *rawNameBuf = tag->buf.raw + nameLen; /* Stop if already stored. Since m_tagStack is a stack, we can stop at the first entry that has already been copied; everything below it in the stack is already been accounted for in a @@ -3142,22 +3147,22 @@ storeRawNames(XML_Parser parser) { if (rawNameLen > (size_t)INT_MAX - nameLen) return XML_FALSE; bufSize = nameLen + rawNameLen; - if (bufSize > (size_t)(tag->bufEnd - tag->buf)) { - char *temp = REALLOC(parser, tag->buf, bufSize); + if (bufSize > (size_t)(tag->bufEnd - tag->buf.raw)) { + char *temp = REALLOC(parser, tag->buf.raw, bufSize); if (temp == NULL) return XML_FALSE; - /* if tag->name.str points to tag->buf (only when namespace + /* if tag->name.str points to tag->buf.str (only when namespace processing is off) then we have to update it */ - if (tag->name.str == (XML_Char *)tag->buf) + if (tag->name.str == tag->buf.str) tag->name.str = (XML_Char *)temp; /* if tag->name.localPart is set (when namespace processing is on) then update it as well, since it will always point into tag->buf */ if (tag->name.localPart) tag->name.localPart - = (XML_Char *)temp + (tag->name.localPart - (XML_Char *)tag->buf); - tag->buf = temp; + = (XML_Char *)temp + (tag->name.localPart - tag->buf.str); + tag->buf.raw = temp; tag->bufEnd = temp + bufSize; rawNameBuf = temp + nameLen; } @@ -3472,12 +3477,12 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, tag = MALLOC(parser, sizeof(TAG)); if (! tag) return XML_ERROR_NO_MEMORY; - tag->buf = MALLOC(parser, INIT_TAG_BUF_SIZE); - if (! tag->buf) { + tag->buf.raw = MALLOC(parser, INIT_TAG_BUF_SIZE); + if (! tag->buf.raw) { FREE(parser, tag); return XML_ERROR_NO_MEMORY; } - tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + tag->bufEnd = tag->buf.raw + INIT_TAG_BUF_SIZE; } tag->bindings = NULL; tag->parent = parser->m_tagStack; @@ -3490,31 +3495,32 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, { const char *rawNameEnd = tag->rawName + tag->rawNameLength; const char *fromPtr = tag->rawName; - toPtr = (XML_Char *)tag->buf; + toPtr = tag->buf.str; for (;;) { - int bufSize; int convLen; const enum XML_Convert_Result convert_res = XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); - convLen = (int)(toPtr - (XML_Char *)tag->buf); + convLen = (int)(toPtr - tag->buf.str); if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) { tag->name.strLen = convLen; break; } - bufSize = (int)(tag->bufEnd - tag->buf) << 1; + if (SIZE_MAX / 2 < (size_t)(tag->bufEnd - tag->buf.raw)) + return XML_ERROR_NO_MEMORY; + const size_t bufSize = (size_t)(tag->bufEnd - tag->buf.raw) * 2; { - char *temp = REALLOC(parser, tag->buf, bufSize); + char *temp = REALLOC(parser, tag->buf.raw, bufSize); if (temp == NULL) return XML_ERROR_NO_MEMORY; - tag->buf = temp; + tag->buf.raw = temp; tag->bufEnd = temp + bufSize; toPtr = (XML_Char *)temp + convLen; } } } - tag->name.str = (XML_Char *)tag->buf; + tag->name.str = tag->buf.str; *toPtr = XML_T('\0'); result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account); @@ -3878,7 +3884,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(ATTRIBUTE)) { + if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(ATTRIBUTE)) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } @@ -3897,7 +3903,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ # if UINT_MAX >= SIZE_MAX - if ((unsigned)parser->m_attsSize > (size_t)(-1) / sizeof(XML_AttrInfo)) { + if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) { parser->m_attsSize = oldAttsSize; return XML_ERROR_NO_MEMORY; } @@ -4073,7 +4079,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if (nsAttsSize > (size_t)(-1) / sizeof(NS_ATT)) { + if (nsAttsSize > SIZE_MAX / sizeof(NS_ATT)) { /* Restore actual size of memory in m_nsAtts */ parser->m_nsAttsPower = oldNsAttsPower; return XML_ERROR_NO_MEMORY; @@ -4256,7 +4262,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((unsigned)(n + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + if ((unsigned)(n + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } #endif @@ -4502,7 +4508,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } #endif @@ -4529,7 +4535,7 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((unsigned)(len + EXPAND_SPARE) > (size_t)(-1) / sizeof(XML_Char)) { + if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) { return XML_ERROR_NO_MEMORY; } #endif @@ -5920,15 +5926,18 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if (parser->m_groupSize > (size_t)(-1) / sizeof(int)) { + if (parser->m_groupSize > SIZE_MAX / sizeof(int)) { + parser->m_groupSize /= 2; return XML_ERROR_NO_MEMORY; } #endif int *const new_scaff_index = REALLOC( parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int)); - if (new_scaff_index == NULL) + if (new_scaff_index == NULL) { + parser->m_groupSize /= 2; return XML_ERROR_NO_MEMORY; + } dtd->scaffIndex = new_scaff_index; } } else { @@ -7190,7 +7199,7 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((unsigned)count > (size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE)) { + if ((unsigned)count > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { return 0; } #endif @@ -7666,8 +7675,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, * from -Wtype-limits on platforms where * sizeof(int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if ((size_t)oldE->nDefaultAtts - > ((size_t)(-1) / sizeof(DEFAULT_ATTRIBUTE))) { + if ((size_t)oldE->nDefaultAtts > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) { return 0; } #endif @@ -7869,7 +7877,7 @@ lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) { unsigned long newMask = (unsigned long)newSize - 1; /* Detect and prevent integer overflow */ - if (newSize > (size_t)(-1) / sizeof(NAMED *)) { + if (newSize > SIZE_MAX / sizeof(NAMED *)) { return NULL; } @@ -8105,7 +8113,7 @@ poolBytesToAllocateFor(int blockSize) { static XML_Bool FASTCALL poolGrow(STRING_POOL *pool) { if (pool->freeBlocks) { - if (pool->start == 0) { + if (pool->start == NULL) { pool->blocks = pool->freeBlocks; pool->freeBlocks = pool->freeBlocks->next; pool->blocks->next = NULL; @@ -8217,7 +8225,7 @@ nextScaffoldPart(XML_Parser parser) { * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if (parser->m_groupSize > ((size_t)(-1) / sizeof(int))) { + if (parser->m_groupSize > SIZE_MAX / sizeof(int)) { return -1; } #endif @@ -8244,7 +8252,7 @@ nextScaffoldPart(XML_Parser parser) { * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if (dtd->scaffSize > (size_t)(-1) / 2u / sizeof(CONTENT_SCAFFOLD)) { + if (dtd->scaffSize > SIZE_MAX / 2u / sizeof(CONTENT_SCAFFOLD)) { return -1; } #endif @@ -8294,15 +8302,15 @@ build_model(XML_Parser parser) { * from -Wtype-limits on platforms where * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */ #if UINT_MAX >= SIZE_MAX - if (dtd->scaffCount > (size_t)(-1) / sizeof(XML_Content)) { + if (dtd->scaffCount > SIZE_MAX / sizeof(XML_Content)) { return NULL; } - if (dtd->contentStringLen > (size_t)(-1) / sizeof(XML_Char)) { + if (dtd->contentStringLen > SIZE_MAX / sizeof(XML_Char)) { return NULL; } #endif if (dtd->scaffCount * sizeof(XML_Content) - > (size_t)(-1) - dtd->contentStringLen * sizeof(XML_Char)) { + > SIZE_MAX - dtd->contentStringLen * sizeof(XML_Char)) { return NULL; } diff --git a/Modules/expat/xmlrole.c b/Modules/expat/xmlrole.c index 2c48bf40867953..d56bee82dd2d13 100644 --- a/Modules/expat/xmlrole.c +++ b/Modules/expat/xmlrole.c @@ -16,6 +16,7 @@ Copyright (c) 2017 Rhodri James Copyright (c) 2019 David Loffredo Copyright (c) 2021 Donghee Na + Copyright (c) 2025 Alfonso Gregory Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -46,7 +47,6 @@ # include "winconfig.h" #endif -#include "expat_external.h" #include "internal.h" #include "xmlrole.h" #include "ascii.h" diff --git a/Modules/expat/xmltok.c b/Modules/expat/xmltok.c index 95d5e84b67f11c..32cd5f147e9322 100644 --- a/Modules/expat/xmltok.c +++ b/Modules/expat/xmltok.c @@ -24,6 +24,7 @@ Copyright (c) 2022 Martin Ettl Copyright (c) 2022 Sean McBride Copyright (c) 2023 Hanno Böck + Copyright (c) 2025 Alfonso Gregory Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -56,7 +57,6 @@ # include "winconfig.h" #endif -#include "expat_external.h" #include "internal.h" #include "xmltok.h" #include "nametab.h" diff --git a/Modules/expat/xmltok_ns.c b/Modules/expat/xmltok_ns.c index fbdd3e3c7b7999..810ca2c6d0485e 100644 --- a/Modules/expat/xmltok_ns.c +++ b/Modules/expat/xmltok_ns.c @@ -12,6 +12,7 @@ Copyright (c) 2002 Fred L. Drake, Jr. Copyright (c) 2002-2006 Karl Waclawek Copyright (c) 2017-2021 Sebastian Pipping + Copyright (c) 2025 Alfonso Gregory Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -98,13 +99,13 @@ NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) { int i; XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); if (ptr != end) - return 0; + return NULL; *p = 0; if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) return enc; i = getEncodingIndex(buf); if (i == UNKNOWN_ENC) - return 0; + return NULL; return NS(encodings)[i]; } From 06f18b767efd98beed62bf854f492401f4b5b3d6 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 5 Feb 2026 14:24:52 +0100 Subject: [PATCH 13/13] The caller must not use that reference after the call. --- Doc/glossary.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 1afdc2db154360..95ff9708185f52 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -1484,8 +1484,10 @@ Glossary steal In Python's C API, "*stealing*" an argument means that ownership of the argument is transferred to the called function. + The caller must not use that reference after the call. Generally, functions that "steal" an argument do so even if they fail. - See also :ref:`api-refcountdetails`. + + See :ref:`api-refcountdetails` for a full explanation. strong reference In Python's C API, a strong reference is a reference to an object