From 561e7068ccf89f8fbd513e42313917254f470416 Mon Sep 17 00:00:00 2001 From: fatelei Date: Thu, 18 Dec 2025 11:43:38 +0800 Subject: [PATCH 001/105] gh-142884: Use-After-Free Vulnerability Fixed in CPython array.array.tofile() --- Lib/test/test_array.py | 15 ++++++++++ ...-12-18-11-41-37.gh-issue-142884.kjgukd.rst | 1 + Modules/arraymodule.c | 30 +++++++++++++------ 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-18-11-41-37.gh-issue-142884.kjgukd.rst diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 83b3c978da3581..8cb4ba1de19cf7 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -1367,6 +1367,21 @@ def test_frombytearray(self): b = array.array(self.typecode, a) self.assertEqual(a, b) + def test_tofile_use_after_free(self): + CHUNK = 64 * 1024 + victim = array.array('B', b'\0' * (CHUNK * 2)) + + class Writer: + armed = True + def write(self, data): + if Writer.armed: + Writer.armed = False + victim.clear() + return 0 + + victim.tofile(Writer()) + + class IntegerNumberTest(NumberTest): def test_type_error(self): a = array.array(self.typecode) diff --git a/Misc/NEWS.d/next/Library/2025-12-18-11-41-37.gh-issue-142884.kjgukd.rst b/Misc/NEWS.d/next/Library/2025-12-18-11-41-37.gh-issue-142884.kjgukd.rst new file mode 100644 index 00000000000000..7dd529c21575fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-18-11-41-37.gh-issue-142884.kjgukd.rst @@ -0,0 +1 @@ +Use-After-Free Vulnerability Fixed in CPython array.array.tofile(). diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 729e085c19f006..89700cf3489e8f 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -1587,35 +1587,47 @@ static PyObject * array_array_tofile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f) /*[clinic end generated code: output=4560c628d9c18bc2 input=5a24da7a7b407b52]*/ { - Py_ssize_t nbytes = Py_SIZE(self) * self->ob_descr->itemsize; /* Write 64K blocks at a time */ /* XXX Make the block size settable */ int BLOCKSIZE = 64*1024; - Py_ssize_t nblocks = (nbytes + BLOCKSIZE - 1) / BLOCKSIZE; - Py_ssize_t i; + Py_ssize_t offset = 0; if (Py_SIZE(self) == 0) goto done; - array_state *state = get_array_state_by_class(cls); assert(state != NULL); - for (i = 0; i < nblocks; i++) { - char* ptr = self->ob_item + i*BLOCKSIZE; + while (1) { + if (self->ob_item == NULL || Py_SIZE(self) == 0) { + break; + } + + Py_ssize_t current_nbytes = Py_SIZE(self) * self->ob_descr->itemsize; + + if (offset >= current_nbytes) { + break; + } + Py_ssize_t size = BLOCKSIZE; + if (offset + size > current_nbytes) { + size = current_nbytes - offset; + } + + char* ptr = self->ob_item + offset; PyObject *bytes, *res; - if (i*BLOCKSIZE + size > nbytes) - size = nbytes - i*BLOCKSIZE; bytes = PyBytes_FromStringAndSize(ptr, size); if (bytes == NULL) return NULL; + res = PyObject_CallMethodOneArg(f, state->str_write, bytes); Py_DECREF(bytes); if (res == NULL) return NULL; - Py_DECREF(res); /* drop write result */ + Py_DECREF(res); + + offset += size; } done: From cbc0851ada9c5bc4018fb5075c82abe2ef4fc4cf Mon Sep 17 00:00:00 2001 From: ivonastojanovic <80911834+ivonastojanovic@users.noreply.github.com> Date: Thu, 18 Dec 2025 11:43:39 +0000 Subject: [PATCH 002/105] gh-138122: Improve bytecode panel (#142910) The bytecode panel appears when a user generates a heatmap with --opcodes and clicks the button to unfold a line and display the bytecode instructions. Currently, an empty space appears on the left where the line number, self, and total columns are displayed. This area should instead extend those columns, rather than leaving a gap. --- .../sampling/_heatmap_assets/heatmap.css | 78 +++++++++++++++++-- .../sampling/_heatmap_assets/heatmap.js | 11 ++- Lib/profiling/sampling/heatmap_collector.py | 12 ++- 3 files changed, 91 insertions(+), 10 deletions(-) diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.css b/Lib/profiling/sampling/_heatmap_assets/heatmap.css index 65a13d7245d5c4..9999cd6760fd49 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.css +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.css @@ -1141,6 +1141,10 @@ .line-samples-cumulative { padding: 0 4px; } + + .bytecode-panel { + margin: 8px 10px 8px 160px; + } } .bytecode-toggle { @@ -1172,13 +1176,77 @@ } .bytecode-panel { - margin-left: 90px; - padding: 8px 15px; - background: var(--bg-secondary); - border-left: 3px solid var(--accent); + background: var(--bg-primary); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: var(--shadow-md); font-family: var(--font-mono); font-size: 12px; - margin-bottom: 4px; + color: var(--text-primary); + line-height: 1.5; + word-wrap: break-word; + overflow-wrap: break-word; + padding: 0; + margin: 8px 10px 8px 250px; + position: relative; + z-index: 1; + overflow-y: auto; + max-height: 500px; + flex: 1; + transition: padding 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.bytecode-panel.expanded { + padding: 14px; +} + +.bytecode-wrapper { + position: relative; + display: flex; + overflow: visible; + max-height: 0; + opacity: 0; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease-in-out; +} + +.bytecode-wrapper.expanded { + max-height: 600px; + opacity: 1; + transition: max-height 0.5s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease-in-out; +} + +/* Column backdrop matching table header columns (line/self/total) */ +.bytecode-columns { + display: none; + position: absolute; + left: 0; + overflow: hidden; + pointer-events: none; + z-index: 0; +} + +.bytecode-wrapper.expanded .bytecode-columns { + display: flex; + top: 0; + bottom: 0; +} + +.bytecode-panel::-webkit-scrollbar { + width: 8px; +} + +.bytecode-panel::-webkit-scrollbar-track { + background: var(--bg-secondary); + border-radius: 4px; +} + +.bytecode-panel::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 4px; +} + +.bytecode-panel::-webkit-scrollbar-thumb:hover { + background: var(--text-muted); } /* Specialization summary bar */ diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js index 8ac4ef43e53b37..d6a91ef290309b 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -542,20 +542,23 @@ function toggleBytecode(button) { const lineId = lineDiv.id; const lineNum = lineId.replace('line-', ''); const panel = document.getElementById(`bytecode-${lineNum}`); + const wrapper = document.getElementById(`bytecode-wrapper-${lineNum}`); - if (!panel) return; + if (!panel || !wrapper) return; - const isExpanded = panel.style.display !== 'none'; + const isExpanded = panel.classList.contains('expanded'); if (isExpanded) { - panel.style.display = 'none'; + panel.classList.remove('expanded'); + wrapper.classList.remove('expanded'); button.classList.remove('expanded'); button.innerHTML = '▶'; // Right arrow } else { if (!panel.dataset.populated) { populateBytecodePanel(panel, button); } - panel.style.display = 'block'; + panel.classList.add('expanded'); + wrapper.classList.add('expanded'); button.classList.add('expanded'); button.innerHTML = '▼'; // Down arrow } diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py index 5b4c89283be08c..e6701901aa385c 100644 --- a/Lib/profiling/sampling/heatmap_collector.py +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -978,7 +978,17 @@ def _build_line_html(self, line_num: int, line_content: str, f'data-spec-pct="{spec_pct}" ' f'onclick="toggleBytecode(this)" title="Show bytecode">▶' ) - bytecode_panel_html = f' \n' + # Wrapper contains columns + content panel + bytecode_panel_html = ( + f'
\n' + f'
' + f'
' + f'
' + f'
' + f'
\n' + f'
\n' + f'
\n' + ) elif self.opcodes_enabled: # Add invisible spacer to maintain consistent indentation when opcodes are enabled bytecode_btn_html = '
' From fc80096a07a3a1da429e251d062a1cf0422cca41 Mon Sep 17 00:00:00 2001 From: James Date: Thu, 18 Dec 2025 07:17:42 -0500 Subject: [PATCH 003/105] gh-137063: Document that ast node types replaced by Constant are no longer available (#137064) --- Doc/library/ast.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 2e7d0dbc26e5bc..bf37540e5faf42 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -139,12 +139,13 @@ Node classes The :meth:`~object.__repr__` output of :class:`~ast.AST` nodes includes the values of the node fields. -.. deprecated:: 3.8 +.. deprecated-removed:: 3.8 3.14 - Old classes :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`, - :class:`!ast.NameConstant` and :class:`!ast.Ellipsis` are still available, - but they will be removed in future Python releases. In the meantime, - instantiating them will return an instance of a different class. + Previous versions of Python provided the AST classes :class:`!ast.Num`, + :class:`!ast.Str`, :class:`!ast.Bytes`, :class:`!ast.NameConstant` and + :class:`!ast.Ellipsis`, which were deprecated in Python 3.8. These classes + were removed in Python 3.14, and their functionality has been replaced with + :class:`ast.Constant`. .. deprecated:: 3.9 @@ -2419,12 +2420,12 @@ and classes for traversing abstract syntax trees: during traversal. For this a special visitor exists (:class:`NodeTransformer`) that allows modifications. - .. deprecated:: 3.8 + .. deprecated-removed:: 3.8 3.14 Methods :meth:`!visit_Num`, :meth:`!visit_Str`, :meth:`!visit_Bytes`, - :meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` are deprecated - now and will not be called in future Python versions. Add the - :meth:`visit_Constant` method to handle all constant nodes. + :meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` will not be called + in Python 3.14+. Add the :meth:`visit_Constant` method instead to handle + all constant nodes. .. class:: NodeTransformer() From 71a7cb8887cd2974de323e2fd8d0f1435789389c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 18 Dec 2025 21:33:18 +0900 Subject: [PATCH 004/105] gh-134584: Remove redundant refcount from _BINARY_OP_ADD_UNICODE (gh-142825) --- Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_uop_ids.h | 1463 ++++++++++----------- Include/internal/pycore_uop_metadata.h | 26 +- Lib/test/test_capi/test_opt.py | 16 + Python/bytecodes.c | 14 +- Python/executor_cases.c.h | 89 +- Python/generated_cases.c.h | 24 +- Python/optimizer_bytecodes.c | 12 +- Python/optimizer_cases.c.h | 42 +- 9 files changed, 859 insertions(+), 831 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index a4f1f50e96d6d1..906ea0db0a5fe0 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1081,7 +1081,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, - [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG }, + [BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, @@ -1331,7 +1331,7 @@ _PyOpcode_macro_expansion[256] = { [BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 } } }, [BINARY_OP_ADD_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_ADD_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_ADD_UNICODE] = { .nuops = 5, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } }, [BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } }, [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 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 8678ccf5e1b823..f73aad9de1c0bf 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -365,738 +365,737 @@ extern "C" { #define _BINARY_OP_ADD_INT_r03 558 #define _BINARY_OP_ADD_INT_r13 559 #define _BINARY_OP_ADD_INT_r23 560 -#define _BINARY_OP_ADD_UNICODE_r01 561 -#define _BINARY_OP_ADD_UNICODE_r11 562 -#define _BINARY_OP_ADD_UNICODE_r21 563 -#define _BINARY_OP_ADD_UNICODE_r32 564 -#define _BINARY_OP_EXTEND_r21 565 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r20 566 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 567 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 568 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 569 -#define _BINARY_OP_MULTIPLY_INT_r03 570 -#define _BINARY_OP_MULTIPLY_INT_r13 571 -#define _BINARY_OP_MULTIPLY_INT_r23 572 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 573 -#define _BINARY_OP_SUBSCR_DICT_r21 574 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 575 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 576 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 577 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 578 -#define _BINARY_OP_SUBSCR_LIST_INT_r21 579 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 580 -#define _BINARY_OP_SUBSCR_STR_INT_r21 581 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r21 582 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 583 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 584 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 585 -#define _BINARY_OP_SUBTRACT_INT_r03 586 -#define _BINARY_OP_SUBTRACT_INT_r13 587 -#define _BINARY_OP_SUBTRACT_INT_r23 588 -#define _BINARY_SLICE_r31 589 -#define _BUILD_INTERPOLATION_r01 590 -#define _BUILD_LIST_r01 591 -#define _BUILD_MAP_r01 592 -#define _BUILD_SET_r01 593 -#define _BUILD_SLICE_r01 594 -#define _BUILD_STRING_r01 595 -#define _BUILD_TEMPLATE_r21 596 -#define _BUILD_TUPLE_r01 597 -#define _CALL_BUILTIN_CLASS_r01 598 -#define _CALL_BUILTIN_FAST_r01 599 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 600 -#define _CALL_BUILTIN_O_r03 601 -#define _CALL_INTRINSIC_1_r11 602 -#define _CALL_INTRINSIC_2_r21 603 -#define _CALL_ISINSTANCE_r31 604 -#define _CALL_KW_NON_PY_r11 605 -#define _CALL_LEN_r33 606 -#define _CALL_LIST_APPEND_r02 607 -#define _CALL_LIST_APPEND_r12 608 -#define _CALL_LIST_APPEND_r22 609 -#define _CALL_LIST_APPEND_r32 610 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 611 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 612 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 613 -#define _CALL_METHOD_DESCRIPTOR_O_r01 614 -#define _CALL_NON_PY_GENERAL_r01 615 -#define _CALL_STR_1_r32 616 -#define _CALL_TUPLE_1_r32 617 -#define _CALL_TYPE_1_r31 618 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 619 -#define _CHECK_ATTR_CLASS_r01 620 -#define _CHECK_ATTR_CLASS_r11 621 -#define _CHECK_ATTR_CLASS_r22 622 -#define _CHECK_ATTR_CLASS_r33 623 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 624 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 625 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 626 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 627 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 628 -#define _CHECK_EG_MATCH_r22 629 -#define _CHECK_EXC_MATCH_r22 630 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 631 -#define _CHECK_FUNCTION_VERSION_r00 632 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 633 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 634 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 635 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 636 -#define _CHECK_FUNCTION_VERSION_KW_r11 637 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 638 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 639 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 640 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 641 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 642 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 643 -#define _CHECK_METHOD_VERSION_r00 644 -#define _CHECK_METHOD_VERSION_KW_r11 645 -#define _CHECK_PEP_523_r00 646 -#define _CHECK_PEP_523_r11 647 -#define _CHECK_PEP_523_r22 648 -#define _CHECK_PEP_523_r33 649 -#define _CHECK_PERIODIC_r00 650 -#define _CHECK_PERIODIC_AT_END_r00 651 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 652 -#define _CHECK_RECURSION_REMAINING_r00 653 -#define _CHECK_RECURSION_REMAINING_r11 654 -#define _CHECK_RECURSION_REMAINING_r22 655 -#define _CHECK_RECURSION_REMAINING_r33 656 -#define _CHECK_STACK_SPACE_r00 657 -#define _CHECK_STACK_SPACE_OPERAND_r00 658 -#define _CHECK_STACK_SPACE_OPERAND_r11 659 -#define _CHECK_STACK_SPACE_OPERAND_r22 660 -#define _CHECK_STACK_SPACE_OPERAND_r33 661 -#define _CHECK_VALIDITY_r00 662 -#define _CHECK_VALIDITY_r11 663 -#define _CHECK_VALIDITY_r22 664 -#define _CHECK_VALIDITY_r33 665 -#define _COLD_DYNAMIC_EXIT_r00 666 -#define _COLD_EXIT_r00 667 -#define _COMPARE_OP_r21 668 -#define _COMPARE_OP_FLOAT_r01 669 -#define _COMPARE_OP_FLOAT_r11 670 -#define _COMPARE_OP_FLOAT_r21 671 -#define _COMPARE_OP_FLOAT_r32 672 -#define _COMPARE_OP_INT_r23 673 -#define _COMPARE_OP_STR_r21 674 -#define _CONTAINS_OP_r21 675 -#define _CONTAINS_OP_DICT_r21 676 -#define _CONTAINS_OP_SET_r21 677 -#define _CONVERT_VALUE_r11 678 -#define _COPY_r01 679 -#define _COPY_1_r02 680 -#define _COPY_1_r12 681 -#define _COPY_1_r23 682 -#define _COPY_2_r03 683 -#define _COPY_2_r13 684 -#define _COPY_2_r23 685 -#define _COPY_3_r03 686 -#define _COPY_3_r13 687 -#define _COPY_3_r23 688 -#define _COPY_3_r33 689 -#define _COPY_FREE_VARS_r00 690 -#define _COPY_FREE_VARS_r11 691 -#define _COPY_FREE_VARS_r22 692 -#define _COPY_FREE_VARS_r33 693 -#define _CREATE_INIT_FRAME_r01 694 -#define _DELETE_ATTR_r10 695 -#define _DELETE_DEREF_r00 696 -#define _DELETE_FAST_r00 697 -#define _DELETE_GLOBAL_r00 698 -#define _DELETE_NAME_r00 699 -#define _DELETE_SUBSCR_r20 700 -#define _DEOPT_r00 701 -#define _DEOPT_r10 702 -#define _DEOPT_r20 703 -#define _DEOPT_r30 704 -#define _DICT_MERGE_r10 705 -#define _DICT_UPDATE_r10 706 -#define _DO_CALL_r01 707 -#define _DO_CALL_FUNCTION_EX_r31 708 -#define _DO_CALL_KW_r11 709 -#define _DYNAMIC_EXIT_r00 710 -#define _DYNAMIC_EXIT_r10 711 -#define _DYNAMIC_EXIT_r20 712 -#define _DYNAMIC_EXIT_r30 713 -#define _END_FOR_r10 714 -#define _END_SEND_r21 715 -#define _ERROR_POP_N_r00 716 -#define _EXIT_INIT_CHECK_r10 717 -#define _EXIT_TRACE_r00 718 -#define _EXIT_TRACE_r10 719 -#define _EXIT_TRACE_r20 720 -#define _EXIT_TRACE_r30 721 -#define _EXPAND_METHOD_r00 722 -#define _EXPAND_METHOD_KW_r11 723 -#define _FATAL_ERROR_r00 724 -#define _FATAL_ERROR_r11 725 -#define _FATAL_ERROR_r22 726 -#define _FATAL_ERROR_r33 727 -#define _FORMAT_SIMPLE_r11 728 -#define _FORMAT_WITH_SPEC_r21 729 -#define _FOR_ITER_r23 730 -#define _FOR_ITER_GEN_FRAME_r23 731 -#define _FOR_ITER_TIER_TWO_r23 732 -#define _GET_AITER_r11 733 -#define _GET_ANEXT_r12 734 -#define _GET_AWAITABLE_r11 735 -#define _GET_ITER_r12 736 -#define _GET_LEN_r12 737 -#define _GET_YIELD_FROM_ITER_r11 738 -#define _GUARD_BINARY_OP_EXTEND_r22 739 -#define _GUARD_CALLABLE_ISINSTANCE_r03 740 -#define _GUARD_CALLABLE_ISINSTANCE_r13 741 -#define _GUARD_CALLABLE_ISINSTANCE_r23 742 -#define _GUARD_CALLABLE_ISINSTANCE_r33 743 -#define _GUARD_CALLABLE_LEN_r03 744 -#define _GUARD_CALLABLE_LEN_r13 745 -#define _GUARD_CALLABLE_LEN_r23 746 -#define _GUARD_CALLABLE_LEN_r33 747 -#define _GUARD_CALLABLE_LIST_APPEND_r03 748 -#define _GUARD_CALLABLE_LIST_APPEND_r13 749 -#define _GUARD_CALLABLE_LIST_APPEND_r23 750 -#define _GUARD_CALLABLE_LIST_APPEND_r33 751 -#define _GUARD_CALLABLE_STR_1_r03 752 -#define _GUARD_CALLABLE_STR_1_r13 753 -#define _GUARD_CALLABLE_STR_1_r23 754 -#define _GUARD_CALLABLE_STR_1_r33 755 -#define _GUARD_CALLABLE_TUPLE_1_r03 756 -#define _GUARD_CALLABLE_TUPLE_1_r13 757 -#define _GUARD_CALLABLE_TUPLE_1_r23 758 -#define _GUARD_CALLABLE_TUPLE_1_r33 759 -#define _GUARD_CALLABLE_TYPE_1_r03 760 -#define _GUARD_CALLABLE_TYPE_1_r13 761 -#define _GUARD_CALLABLE_TYPE_1_r23 762 -#define _GUARD_CALLABLE_TYPE_1_r33 763 -#define _GUARD_DORV_NO_DICT_r01 764 -#define _GUARD_DORV_NO_DICT_r11 765 -#define _GUARD_DORV_NO_DICT_r22 766 -#define _GUARD_DORV_NO_DICT_r33 767 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 768 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 769 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 770 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 771 -#define _GUARD_GLOBALS_VERSION_r00 772 -#define _GUARD_GLOBALS_VERSION_r11 773 -#define _GUARD_GLOBALS_VERSION_r22 774 -#define _GUARD_GLOBALS_VERSION_r33 775 -#define _GUARD_IP_RETURN_GENERATOR_r00 776 -#define _GUARD_IP_RETURN_GENERATOR_r11 777 -#define _GUARD_IP_RETURN_GENERATOR_r22 778 -#define _GUARD_IP_RETURN_GENERATOR_r33 779 -#define _GUARD_IP_RETURN_VALUE_r00 780 -#define _GUARD_IP_RETURN_VALUE_r11 781 -#define _GUARD_IP_RETURN_VALUE_r22 782 -#define _GUARD_IP_RETURN_VALUE_r33 783 -#define _GUARD_IP_YIELD_VALUE_r00 784 -#define _GUARD_IP_YIELD_VALUE_r11 785 -#define _GUARD_IP_YIELD_VALUE_r22 786 -#define _GUARD_IP_YIELD_VALUE_r33 787 -#define _GUARD_IP__PUSH_FRAME_r00 788 -#define _GUARD_IP__PUSH_FRAME_r11 789 -#define _GUARD_IP__PUSH_FRAME_r22 790 -#define _GUARD_IP__PUSH_FRAME_r33 791 -#define _GUARD_IS_FALSE_POP_r00 792 -#define _GUARD_IS_FALSE_POP_r10 793 -#define _GUARD_IS_FALSE_POP_r21 794 -#define _GUARD_IS_FALSE_POP_r32 795 -#define _GUARD_IS_NONE_POP_r00 796 -#define _GUARD_IS_NONE_POP_r10 797 -#define _GUARD_IS_NONE_POP_r21 798 -#define _GUARD_IS_NONE_POP_r32 799 -#define _GUARD_IS_NOT_NONE_POP_r10 800 -#define _GUARD_IS_TRUE_POP_r00 801 -#define _GUARD_IS_TRUE_POP_r10 802 -#define _GUARD_IS_TRUE_POP_r21 803 -#define _GUARD_IS_TRUE_POP_r32 804 -#define _GUARD_KEYS_VERSION_r01 805 -#define _GUARD_KEYS_VERSION_r11 806 -#define _GUARD_KEYS_VERSION_r22 807 -#define _GUARD_KEYS_VERSION_r33 808 -#define _GUARD_NOS_DICT_r02 809 -#define _GUARD_NOS_DICT_r12 810 -#define _GUARD_NOS_DICT_r22 811 -#define _GUARD_NOS_DICT_r33 812 -#define _GUARD_NOS_FLOAT_r02 813 -#define _GUARD_NOS_FLOAT_r12 814 -#define _GUARD_NOS_FLOAT_r22 815 -#define _GUARD_NOS_FLOAT_r33 816 -#define _GUARD_NOS_INT_r02 817 -#define _GUARD_NOS_INT_r12 818 -#define _GUARD_NOS_INT_r22 819 -#define _GUARD_NOS_INT_r33 820 -#define _GUARD_NOS_LIST_r02 821 -#define _GUARD_NOS_LIST_r12 822 -#define _GUARD_NOS_LIST_r22 823 -#define _GUARD_NOS_LIST_r33 824 -#define _GUARD_NOS_NOT_NULL_r02 825 -#define _GUARD_NOS_NOT_NULL_r12 826 -#define _GUARD_NOS_NOT_NULL_r22 827 -#define _GUARD_NOS_NOT_NULL_r33 828 -#define _GUARD_NOS_NULL_r02 829 -#define _GUARD_NOS_NULL_r12 830 -#define _GUARD_NOS_NULL_r22 831 -#define _GUARD_NOS_NULL_r33 832 -#define _GUARD_NOS_OVERFLOWED_r02 833 -#define _GUARD_NOS_OVERFLOWED_r12 834 -#define _GUARD_NOS_OVERFLOWED_r22 835 -#define _GUARD_NOS_OVERFLOWED_r33 836 -#define _GUARD_NOS_TUPLE_r02 837 -#define _GUARD_NOS_TUPLE_r12 838 -#define _GUARD_NOS_TUPLE_r22 839 -#define _GUARD_NOS_TUPLE_r33 840 -#define _GUARD_NOS_UNICODE_r02 841 -#define _GUARD_NOS_UNICODE_r12 842 -#define _GUARD_NOS_UNICODE_r22 843 -#define _GUARD_NOS_UNICODE_r33 844 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 845 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 846 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 847 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 848 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 849 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 850 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 851 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 852 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 853 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 854 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 855 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 856 -#define _GUARD_THIRD_NULL_r03 857 -#define _GUARD_THIRD_NULL_r13 858 -#define _GUARD_THIRD_NULL_r23 859 -#define _GUARD_THIRD_NULL_r33 860 -#define _GUARD_TOS_ANY_SET_r01 861 -#define _GUARD_TOS_ANY_SET_r11 862 -#define _GUARD_TOS_ANY_SET_r22 863 -#define _GUARD_TOS_ANY_SET_r33 864 -#define _GUARD_TOS_DICT_r01 865 -#define _GUARD_TOS_DICT_r11 866 -#define _GUARD_TOS_DICT_r22 867 -#define _GUARD_TOS_DICT_r33 868 -#define _GUARD_TOS_FLOAT_r01 869 -#define _GUARD_TOS_FLOAT_r11 870 -#define _GUARD_TOS_FLOAT_r22 871 -#define _GUARD_TOS_FLOAT_r33 872 -#define _GUARD_TOS_INT_r01 873 -#define _GUARD_TOS_INT_r11 874 -#define _GUARD_TOS_INT_r22 875 -#define _GUARD_TOS_INT_r33 876 -#define _GUARD_TOS_LIST_r01 877 -#define _GUARD_TOS_LIST_r11 878 -#define _GUARD_TOS_LIST_r22 879 -#define _GUARD_TOS_LIST_r33 880 -#define _GUARD_TOS_OVERFLOWED_r01 881 -#define _GUARD_TOS_OVERFLOWED_r11 882 -#define _GUARD_TOS_OVERFLOWED_r22 883 -#define _GUARD_TOS_OVERFLOWED_r33 884 -#define _GUARD_TOS_SLICE_r01 885 -#define _GUARD_TOS_SLICE_r11 886 -#define _GUARD_TOS_SLICE_r22 887 -#define _GUARD_TOS_SLICE_r33 888 -#define _GUARD_TOS_TUPLE_r01 889 -#define _GUARD_TOS_TUPLE_r11 890 -#define _GUARD_TOS_TUPLE_r22 891 -#define _GUARD_TOS_TUPLE_r33 892 -#define _GUARD_TOS_UNICODE_r01 893 -#define _GUARD_TOS_UNICODE_r11 894 -#define _GUARD_TOS_UNICODE_r22 895 -#define _GUARD_TOS_UNICODE_r33 896 -#define _GUARD_TYPE_VERSION_r01 897 -#define _GUARD_TYPE_VERSION_r11 898 -#define _GUARD_TYPE_VERSION_r22 899 -#define _GUARD_TYPE_VERSION_r33 900 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 901 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 902 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 903 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 904 -#define _HANDLE_PENDING_AND_DEOPT_r00 905 -#define _HANDLE_PENDING_AND_DEOPT_r10 906 -#define _HANDLE_PENDING_AND_DEOPT_r20 907 -#define _HANDLE_PENDING_AND_DEOPT_r30 908 -#define _IMPORT_FROM_r12 909 -#define _IMPORT_NAME_r21 910 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 911 -#define _INIT_CALL_PY_EXACT_ARGS_r01 912 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 913 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 914 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 915 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 916 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 917 -#define _INSERT_NULL_r10 918 -#define _INSTRUMENTED_FOR_ITER_r23 919 -#define _INSTRUMENTED_INSTRUCTION_r00 920 -#define _INSTRUMENTED_JUMP_FORWARD_r00 921 -#define _INSTRUMENTED_JUMP_FORWARD_r11 922 -#define _INSTRUMENTED_JUMP_FORWARD_r22 923 -#define _INSTRUMENTED_JUMP_FORWARD_r33 924 -#define _INSTRUMENTED_LINE_r00 925 -#define _INSTRUMENTED_NOT_TAKEN_r00 926 -#define _INSTRUMENTED_NOT_TAKEN_r11 927 -#define _INSTRUMENTED_NOT_TAKEN_r22 928 -#define _INSTRUMENTED_NOT_TAKEN_r33 929 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 930 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 931 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 932 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 933 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 934 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 935 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 936 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 937 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 938 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 939 -#define _IS_NONE_r11 940 -#define _IS_OP_r21 941 -#define _ITER_CHECK_LIST_r02 942 -#define _ITER_CHECK_LIST_r12 943 -#define _ITER_CHECK_LIST_r22 944 -#define _ITER_CHECK_LIST_r33 945 -#define _ITER_CHECK_RANGE_r02 946 -#define _ITER_CHECK_RANGE_r12 947 -#define _ITER_CHECK_RANGE_r22 948 -#define _ITER_CHECK_RANGE_r33 949 -#define _ITER_CHECK_TUPLE_r02 950 -#define _ITER_CHECK_TUPLE_r12 951 -#define _ITER_CHECK_TUPLE_r22 952 -#define _ITER_CHECK_TUPLE_r33 953 -#define _ITER_JUMP_LIST_r02 954 -#define _ITER_JUMP_LIST_r12 955 -#define _ITER_JUMP_LIST_r22 956 -#define _ITER_JUMP_LIST_r33 957 -#define _ITER_JUMP_RANGE_r02 958 -#define _ITER_JUMP_RANGE_r12 959 -#define _ITER_JUMP_RANGE_r22 960 -#define _ITER_JUMP_RANGE_r33 961 -#define _ITER_JUMP_TUPLE_r02 962 -#define _ITER_JUMP_TUPLE_r12 963 -#define _ITER_JUMP_TUPLE_r22 964 -#define _ITER_JUMP_TUPLE_r33 965 -#define _ITER_NEXT_LIST_r23 966 -#define _ITER_NEXT_LIST_TIER_TWO_r23 967 -#define _ITER_NEXT_RANGE_r03 968 -#define _ITER_NEXT_RANGE_r13 969 -#define _ITER_NEXT_RANGE_r23 970 -#define _ITER_NEXT_TUPLE_r03 971 -#define _ITER_NEXT_TUPLE_r13 972 -#define _ITER_NEXT_TUPLE_r23 973 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 974 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 975 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 976 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 977 -#define _JUMP_TO_TOP_r00 978 -#define _LIST_APPEND_r10 979 -#define _LIST_EXTEND_r10 980 -#define _LOAD_ATTR_r10 981 -#define _LOAD_ATTR_CLASS_r11 982 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 983 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 984 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 985 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 986 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 987 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 988 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 989 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 990 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 991 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 992 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 993 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 994 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 995 -#define _LOAD_ATTR_MODULE_r11 996 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 997 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 998 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 999 -#define _LOAD_ATTR_SLOT_r11 1000 -#define _LOAD_ATTR_WITH_HINT_r11 1001 -#define _LOAD_BUILD_CLASS_r01 1002 -#define _LOAD_BYTECODE_r00 1003 -#define _LOAD_COMMON_CONSTANT_r01 1004 -#define _LOAD_COMMON_CONSTANT_r12 1005 -#define _LOAD_COMMON_CONSTANT_r23 1006 -#define _LOAD_CONST_r01 1007 -#define _LOAD_CONST_r12 1008 -#define _LOAD_CONST_r23 1009 -#define _LOAD_CONST_INLINE_r01 1010 -#define _LOAD_CONST_INLINE_r12 1011 -#define _LOAD_CONST_INLINE_r23 1012 -#define _LOAD_CONST_INLINE_BORROW_r01 1013 -#define _LOAD_CONST_INLINE_BORROW_r12 1014 -#define _LOAD_CONST_INLINE_BORROW_r23 1015 -#define _LOAD_CONST_UNDER_INLINE_r02 1016 -#define _LOAD_CONST_UNDER_INLINE_r12 1017 -#define _LOAD_CONST_UNDER_INLINE_r23 1018 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1019 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1020 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1021 -#define _LOAD_DEREF_r01 1022 -#define _LOAD_FAST_r01 1023 -#define _LOAD_FAST_r12 1024 -#define _LOAD_FAST_r23 1025 -#define _LOAD_FAST_0_r01 1026 -#define _LOAD_FAST_0_r12 1027 -#define _LOAD_FAST_0_r23 1028 -#define _LOAD_FAST_1_r01 1029 -#define _LOAD_FAST_1_r12 1030 -#define _LOAD_FAST_1_r23 1031 -#define _LOAD_FAST_2_r01 1032 -#define _LOAD_FAST_2_r12 1033 -#define _LOAD_FAST_2_r23 1034 -#define _LOAD_FAST_3_r01 1035 -#define _LOAD_FAST_3_r12 1036 -#define _LOAD_FAST_3_r23 1037 -#define _LOAD_FAST_4_r01 1038 -#define _LOAD_FAST_4_r12 1039 -#define _LOAD_FAST_4_r23 1040 -#define _LOAD_FAST_5_r01 1041 -#define _LOAD_FAST_5_r12 1042 -#define _LOAD_FAST_5_r23 1043 -#define _LOAD_FAST_6_r01 1044 -#define _LOAD_FAST_6_r12 1045 -#define _LOAD_FAST_6_r23 1046 -#define _LOAD_FAST_7_r01 1047 -#define _LOAD_FAST_7_r12 1048 -#define _LOAD_FAST_7_r23 1049 -#define _LOAD_FAST_AND_CLEAR_r01 1050 -#define _LOAD_FAST_AND_CLEAR_r12 1051 -#define _LOAD_FAST_AND_CLEAR_r23 1052 -#define _LOAD_FAST_BORROW_r01 1053 -#define _LOAD_FAST_BORROW_r12 1054 -#define _LOAD_FAST_BORROW_r23 1055 -#define _LOAD_FAST_BORROW_0_r01 1056 -#define _LOAD_FAST_BORROW_0_r12 1057 -#define _LOAD_FAST_BORROW_0_r23 1058 -#define _LOAD_FAST_BORROW_1_r01 1059 -#define _LOAD_FAST_BORROW_1_r12 1060 -#define _LOAD_FAST_BORROW_1_r23 1061 -#define _LOAD_FAST_BORROW_2_r01 1062 -#define _LOAD_FAST_BORROW_2_r12 1063 -#define _LOAD_FAST_BORROW_2_r23 1064 -#define _LOAD_FAST_BORROW_3_r01 1065 -#define _LOAD_FAST_BORROW_3_r12 1066 -#define _LOAD_FAST_BORROW_3_r23 1067 -#define _LOAD_FAST_BORROW_4_r01 1068 -#define _LOAD_FAST_BORROW_4_r12 1069 -#define _LOAD_FAST_BORROW_4_r23 1070 -#define _LOAD_FAST_BORROW_5_r01 1071 -#define _LOAD_FAST_BORROW_5_r12 1072 -#define _LOAD_FAST_BORROW_5_r23 1073 -#define _LOAD_FAST_BORROW_6_r01 1074 -#define _LOAD_FAST_BORROW_6_r12 1075 -#define _LOAD_FAST_BORROW_6_r23 1076 -#define _LOAD_FAST_BORROW_7_r01 1077 -#define _LOAD_FAST_BORROW_7_r12 1078 -#define _LOAD_FAST_BORROW_7_r23 1079 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1080 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1081 -#define _LOAD_FAST_CHECK_r01 1082 -#define _LOAD_FAST_CHECK_r12 1083 -#define _LOAD_FAST_CHECK_r23 1084 -#define _LOAD_FAST_LOAD_FAST_r02 1085 -#define _LOAD_FAST_LOAD_FAST_r13 1086 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1087 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1088 -#define _LOAD_GLOBAL_r00 1089 -#define _LOAD_GLOBAL_BUILTINS_r01 1090 -#define _LOAD_GLOBAL_MODULE_r01 1091 -#define _LOAD_LOCALS_r01 1092 -#define _LOAD_LOCALS_r12 1093 -#define _LOAD_LOCALS_r23 1094 -#define _LOAD_NAME_r01 1095 -#define _LOAD_SMALL_INT_r01 1096 -#define _LOAD_SMALL_INT_r12 1097 -#define _LOAD_SMALL_INT_r23 1098 -#define _LOAD_SMALL_INT_0_r01 1099 -#define _LOAD_SMALL_INT_0_r12 1100 -#define _LOAD_SMALL_INT_0_r23 1101 -#define _LOAD_SMALL_INT_1_r01 1102 -#define _LOAD_SMALL_INT_1_r12 1103 -#define _LOAD_SMALL_INT_1_r23 1104 -#define _LOAD_SMALL_INT_2_r01 1105 -#define _LOAD_SMALL_INT_2_r12 1106 -#define _LOAD_SMALL_INT_2_r23 1107 -#define _LOAD_SMALL_INT_3_r01 1108 -#define _LOAD_SMALL_INT_3_r12 1109 -#define _LOAD_SMALL_INT_3_r23 1110 -#define _LOAD_SPECIAL_r00 1111 -#define _LOAD_SUPER_ATTR_ATTR_r31 1112 -#define _LOAD_SUPER_ATTR_METHOD_r32 1113 -#define _MAKE_CALLARGS_A_TUPLE_r33 1114 -#define _MAKE_CELL_r00 1115 -#define _MAKE_FUNCTION_r11 1116 -#define _MAKE_WARM_r00 1117 -#define _MAKE_WARM_r11 1118 -#define _MAKE_WARM_r22 1119 -#define _MAKE_WARM_r33 1120 -#define _MAP_ADD_r20 1121 -#define _MATCH_CLASS_r31 1122 -#define _MATCH_KEYS_r23 1123 -#define _MATCH_MAPPING_r02 1124 -#define _MATCH_MAPPING_r12 1125 -#define _MATCH_MAPPING_r23 1126 -#define _MATCH_SEQUENCE_r02 1127 -#define _MATCH_SEQUENCE_r12 1128 -#define _MATCH_SEQUENCE_r23 1129 -#define _MAYBE_EXPAND_METHOD_r00 1130 -#define _MAYBE_EXPAND_METHOD_KW_r11 1131 -#define _MONITOR_CALL_r00 1132 -#define _MONITOR_CALL_KW_r11 1133 -#define _MONITOR_JUMP_BACKWARD_r00 1134 -#define _MONITOR_JUMP_BACKWARD_r11 1135 -#define _MONITOR_JUMP_BACKWARD_r22 1136 -#define _MONITOR_JUMP_BACKWARD_r33 1137 -#define _MONITOR_RESUME_r00 1138 -#define _NOP_r00 1139 -#define _NOP_r11 1140 -#define _NOP_r22 1141 -#define _NOP_r33 1142 -#define _POP_CALL_r20 1143 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1144 -#define _POP_CALL_ONE_r30 1145 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1146 -#define _POP_CALL_TWO_r30 1147 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1148 -#define _POP_EXCEPT_r10 1149 -#define _POP_ITER_r20 1150 -#define _POP_JUMP_IF_FALSE_r00 1151 -#define _POP_JUMP_IF_FALSE_r10 1152 -#define _POP_JUMP_IF_FALSE_r21 1153 -#define _POP_JUMP_IF_FALSE_r32 1154 -#define _POP_JUMP_IF_TRUE_r00 1155 -#define _POP_JUMP_IF_TRUE_r10 1156 -#define _POP_JUMP_IF_TRUE_r21 1157 -#define _POP_JUMP_IF_TRUE_r32 1158 -#define _POP_TOP_r10 1159 -#define _POP_TOP_FLOAT_r00 1160 -#define _POP_TOP_FLOAT_r10 1161 -#define _POP_TOP_FLOAT_r21 1162 -#define _POP_TOP_FLOAT_r32 1163 -#define _POP_TOP_INT_r00 1164 -#define _POP_TOP_INT_r10 1165 -#define _POP_TOP_INT_r21 1166 -#define _POP_TOP_INT_r32 1167 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1168 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1169 -#define _POP_TOP_NOP_r00 1170 -#define _POP_TOP_NOP_r10 1171 -#define _POP_TOP_NOP_r21 1172 -#define _POP_TOP_NOP_r32 1173 -#define _POP_TOP_UNICODE_r00 1174 -#define _POP_TOP_UNICODE_r10 1175 -#define _POP_TOP_UNICODE_r21 1176 -#define _POP_TOP_UNICODE_r32 1177 -#define _POP_TWO_r20 1178 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1179 -#define _PUSH_EXC_INFO_r02 1180 -#define _PUSH_EXC_INFO_r12 1181 -#define _PUSH_EXC_INFO_r23 1182 -#define _PUSH_FRAME_r10 1183 -#define _PUSH_NULL_r01 1184 -#define _PUSH_NULL_r12 1185 -#define _PUSH_NULL_r23 1186 -#define _PUSH_NULL_CONDITIONAL_r00 1187 -#define _PY_FRAME_GENERAL_r01 1188 -#define _PY_FRAME_KW_r11 1189 -#define _QUICKEN_RESUME_r00 1190 -#define _QUICKEN_RESUME_r11 1191 -#define _QUICKEN_RESUME_r22 1192 -#define _QUICKEN_RESUME_r33 1193 -#define _REPLACE_WITH_TRUE_r11 1194 -#define _RESUME_CHECK_r00 1195 -#define _RESUME_CHECK_r11 1196 -#define _RESUME_CHECK_r22 1197 -#define _RESUME_CHECK_r33 1198 -#define _RETURN_GENERATOR_r01 1199 -#define _RETURN_VALUE_r11 1200 -#define _SAVE_RETURN_OFFSET_r00 1201 -#define _SAVE_RETURN_OFFSET_r11 1202 -#define _SAVE_RETURN_OFFSET_r22 1203 -#define _SAVE_RETURN_OFFSET_r33 1204 -#define _SEND_r22 1205 -#define _SEND_GEN_FRAME_r22 1206 -#define _SETUP_ANNOTATIONS_r00 1207 -#define _SET_ADD_r10 1208 -#define _SET_FUNCTION_ATTRIBUTE_r01 1209 -#define _SET_FUNCTION_ATTRIBUTE_r11 1210 -#define _SET_FUNCTION_ATTRIBUTE_r21 1211 -#define _SET_FUNCTION_ATTRIBUTE_r32 1212 -#define _SET_IP_r00 1213 -#define _SET_IP_r11 1214 -#define _SET_IP_r22 1215 -#define _SET_IP_r33 1216 -#define _SET_UPDATE_r10 1217 -#define _SPILL_OR_RELOAD_r01 1218 -#define _SPILL_OR_RELOAD_r02 1219 -#define _SPILL_OR_RELOAD_r03 1220 -#define _SPILL_OR_RELOAD_r10 1221 -#define _SPILL_OR_RELOAD_r12 1222 -#define _SPILL_OR_RELOAD_r13 1223 -#define _SPILL_OR_RELOAD_r20 1224 -#define _SPILL_OR_RELOAD_r21 1225 -#define _SPILL_OR_RELOAD_r23 1226 -#define _SPILL_OR_RELOAD_r30 1227 -#define _SPILL_OR_RELOAD_r31 1228 -#define _SPILL_OR_RELOAD_r32 1229 -#define _START_EXECUTOR_r00 1230 -#define _STORE_ATTR_r20 1231 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1232 -#define _STORE_ATTR_SLOT_r21 1233 -#define _STORE_ATTR_WITH_HINT_r21 1234 -#define _STORE_DEREF_r10 1235 -#define _STORE_FAST_r10 1236 -#define _STORE_FAST_0_r10 1237 -#define _STORE_FAST_1_r10 1238 -#define _STORE_FAST_2_r10 1239 -#define _STORE_FAST_3_r10 1240 -#define _STORE_FAST_4_r10 1241 -#define _STORE_FAST_5_r10 1242 -#define _STORE_FAST_6_r10 1243 -#define _STORE_FAST_7_r10 1244 -#define _STORE_FAST_LOAD_FAST_r11 1245 -#define _STORE_FAST_STORE_FAST_r20 1246 -#define _STORE_GLOBAL_r10 1247 -#define _STORE_NAME_r10 1248 -#define _STORE_SLICE_r30 1249 -#define _STORE_SUBSCR_r30 1250 -#define _STORE_SUBSCR_DICT_r31 1251 -#define _STORE_SUBSCR_LIST_INT_r32 1252 -#define _SWAP_r11 1253 -#define _SWAP_2_r02 1254 -#define _SWAP_2_r12 1255 -#define _SWAP_2_r22 1256 -#define _SWAP_2_r33 1257 -#define _SWAP_3_r03 1258 -#define _SWAP_3_r13 1259 -#define _SWAP_3_r23 1260 -#define _SWAP_3_r33 1261 -#define _TIER2_RESUME_CHECK_r00 1262 -#define _TIER2_RESUME_CHECK_r11 1263 -#define _TIER2_RESUME_CHECK_r22 1264 -#define _TIER2_RESUME_CHECK_r33 1265 -#define _TO_BOOL_r11 1266 -#define _TO_BOOL_BOOL_r01 1267 -#define _TO_BOOL_BOOL_r11 1268 -#define _TO_BOOL_BOOL_r22 1269 -#define _TO_BOOL_BOOL_r33 1270 -#define _TO_BOOL_INT_r11 1271 -#define _TO_BOOL_LIST_r11 1272 -#define _TO_BOOL_NONE_r01 1273 -#define _TO_BOOL_NONE_r11 1274 -#define _TO_BOOL_NONE_r22 1275 -#define _TO_BOOL_NONE_r33 1276 -#define _TO_BOOL_STR_r11 1277 -#define _TRACE_RECORD_r00 1278 -#define _UNARY_INVERT_r11 1279 -#define _UNARY_NEGATIVE_r11 1280 -#define _UNARY_NOT_r01 1281 -#define _UNARY_NOT_r11 1282 -#define _UNARY_NOT_r22 1283 -#define _UNARY_NOT_r33 1284 -#define _UNPACK_EX_r10 1285 -#define _UNPACK_SEQUENCE_r10 1286 -#define _UNPACK_SEQUENCE_LIST_r10 1287 -#define _UNPACK_SEQUENCE_TUPLE_r10 1288 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1289 -#define _WITH_EXCEPT_START_r33 1290 -#define _YIELD_VALUE_r11 1291 -#define MAX_UOP_REGS_ID 1291 +#define _BINARY_OP_ADD_UNICODE_r03 561 +#define _BINARY_OP_ADD_UNICODE_r13 562 +#define _BINARY_OP_ADD_UNICODE_r23 563 +#define _BINARY_OP_EXTEND_r21 564 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r20 565 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 566 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 567 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 568 +#define _BINARY_OP_MULTIPLY_INT_r03 569 +#define _BINARY_OP_MULTIPLY_INT_r13 570 +#define _BINARY_OP_MULTIPLY_INT_r23 571 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 572 +#define _BINARY_OP_SUBSCR_DICT_r21 573 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 574 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 575 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 576 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 577 +#define _BINARY_OP_SUBSCR_LIST_INT_r21 578 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 579 +#define _BINARY_OP_SUBSCR_STR_INT_r21 580 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r21 581 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 582 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 583 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 584 +#define _BINARY_OP_SUBTRACT_INT_r03 585 +#define _BINARY_OP_SUBTRACT_INT_r13 586 +#define _BINARY_OP_SUBTRACT_INT_r23 587 +#define _BINARY_SLICE_r31 588 +#define _BUILD_INTERPOLATION_r01 589 +#define _BUILD_LIST_r01 590 +#define _BUILD_MAP_r01 591 +#define _BUILD_SET_r01 592 +#define _BUILD_SLICE_r01 593 +#define _BUILD_STRING_r01 594 +#define _BUILD_TEMPLATE_r21 595 +#define _BUILD_TUPLE_r01 596 +#define _CALL_BUILTIN_CLASS_r01 597 +#define _CALL_BUILTIN_FAST_r01 598 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 599 +#define _CALL_BUILTIN_O_r03 600 +#define _CALL_INTRINSIC_1_r11 601 +#define _CALL_INTRINSIC_2_r21 602 +#define _CALL_ISINSTANCE_r31 603 +#define _CALL_KW_NON_PY_r11 604 +#define _CALL_LEN_r33 605 +#define _CALL_LIST_APPEND_r02 606 +#define _CALL_LIST_APPEND_r12 607 +#define _CALL_LIST_APPEND_r22 608 +#define _CALL_LIST_APPEND_r32 609 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 610 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 611 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 612 +#define _CALL_METHOD_DESCRIPTOR_O_r01 613 +#define _CALL_NON_PY_GENERAL_r01 614 +#define _CALL_STR_1_r32 615 +#define _CALL_TUPLE_1_r32 616 +#define _CALL_TYPE_1_r31 617 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 618 +#define _CHECK_ATTR_CLASS_r01 619 +#define _CHECK_ATTR_CLASS_r11 620 +#define _CHECK_ATTR_CLASS_r22 621 +#define _CHECK_ATTR_CLASS_r33 622 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 623 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 624 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 625 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 626 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 627 +#define _CHECK_EG_MATCH_r22 628 +#define _CHECK_EXC_MATCH_r22 629 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 630 +#define _CHECK_FUNCTION_VERSION_r00 631 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 632 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 633 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 634 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 635 +#define _CHECK_FUNCTION_VERSION_KW_r11 636 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 637 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 638 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 639 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 640 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 641 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 642 +#define _CHECK_METHOD_VERSION_r00 643 +#define _CHECK_METHOD_VERSION_KW_r11 644 +#define _CHECK_PEP_523_r00 645 +#define _CHECK_PEP_523_r11 646 +#define _CHECK_PEP_523_r22 647 +#define _CHECK_PEP_523_r33 648 +#define _CHECK_PERIODIC_r00 649 +#define _CHECK_PERIODIC_AT_END_r00 650 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 651 +#define _CHECK_RECURSION_REMAINING_r00 652 +#define _CHECK_RECURSION_REMAINING_r11 653 +#define _CHECK_RECURSION_REMAINING_r22 654 +#define _CHECK_RECURSION_REMAINING_r33 655 +#define _CHECK_STACK_SPACE_r00 656 +#define _CHECK_STACK_SPACE_OPERAND_r00 657 +#define _CHECK_STACK_SPACE_OPERAND_r11 658 +#define _CHECK_STACK_SPACE_OPERAND_r22 659 +#define _CHECK_STACK_SPACE_OPERAND_r33 660 +#define _CHECK_VALIDITY_r00 661 +#define _CHECK_VALIDITY_r11 662 +#define _CHECK_VALIDITY_r22 663 +#define _CHECK_VALIDITY_r33 664 +#define _COLD_DYNAMIC_EXIT_r00 665 +#define _COLD_EXIT_r00 666 +#define _COMPARE_OP_r21 667 +#define _COMPARE_OP_FLOAT_r01 668 +#define _COMPARE_OP_FLOAT_r11 669 +#define _COMPARE_OP_FLOAT_r21 670 +#define _COMPARE_OP_FLOAT_r32 671 +#define _COMPARE_OP_INT_r23 672 +#define _COMPARE_OP_STR_r21 673 +#define _CONTAINS_OP_r21 674 +#define _CONTAINS_OP_DICT_r21 675 +#define _CONTAINS_OP_SET_r21 676 +#define _CONVERT_VALUE_r11 677 +#define _COPY_r01 678 +#define _COPY_1_r02 679 +#define _COPY_1_r12 680 +#define _COPY_1_r23 681 +#define _COPY_2_r03 682 +#define _COPY_2_r13 683 +#define _COPY_2_r23 684 +#define _COPY_3_r03 685 +#define _COPY_3_r13 686 +#define _COPY_3_r23 687 +#define _COPY_3_r33 688 +#define _COPY_FREE_VARS_r00 689 +#define _COPY_FREE_VARS_r11 690 +#define _COPY_FREE_VARS_r22 691 +#define _COPY_FREE_VARS_r33 692 +#define _CREATE_INIT_FRAME_r01 693 +#define _DELETE_ATTR_r10 694 +#define _DELETE_DEREF_r00 695 +#define _DELETE_FAST_r00 696 +#define _DELETE_GLOBAL_r00 697 +#define _DELETE_NAME_r00 698 +#define _DELETE_SUBSCR_r20 699 +#define _DEOPT_r00 700 +#define _DEOPT_r10 701 +#define _DEOPT_r20 702 +#define _DEOPT_r30 703 +#define _DICT_MERGE_r10 704 +#define _DICT_UPDATE_r10 705 +#define _DO_CALL_r01 706 +#define _DO_CALL_FUNCTION_EX_r31 707 +#define _DO_CALL_KW_r11 708 +#define _DYNAMIC_EXIT_r00 709 +#define _DYNAMIC_EXIT_r10 710 +#define _DYNAMIC_EXIT_r20 711 +#define _DYNAMIC_EXIT_r30 712 +#define _END_FOR_r10 713 +#define _END_SEND_r21 714 +#define _ERROR_POP_N_r00 715 +#define _EXIT_INIT_CHECK_r10 716 +#define _EXIT_TRACE_r00 717 +#define _EXIT_TRACE_r10 718 +#define _EXIT_TRACE_r20 719 +#define _EXIT_TRACE_r30 720 +#define _EXPAND_METHOD_r00 721 +#define _EXPAND_METHOD_KW_r11 722 +#define _FATAL_ERROR_r00 723 +#define _FATAL_ERROR_r11 724 +#define _FATAL_ERROR_r22 725 +#define _FATAL_ERROR_r33 726 +#define _FORMAT_SIMPLE_r11 727 +#define _FORMAT_WITH_SPEC_r21 728 +#define _FOR_ITER_r23 729 +#define _FOR_ITER_GEN_FRAME_r23 730 +#define _FOR_ITER_TIER_TWO_r23 731 +#define _GET_AITER_r11 732 +#define _GET_ANEXT_r12 733 +#define _GET_AWAITABLE_r11 734 +#define _GET_ITER_r12 735 +#define _GET_LEN_r12 736 +#define _GET_YIELD_FROM_ITER_r11 737 +#define _GUARD_BINARY_OP_EXTEND_r22 738 +#define _GUARD_CALLABLE_ISINSTANCE_r03 739 +#define _GUARD_CALLABLE_ISINSTANCE_r13 740 +#define _GUARD_CALLABLE_ISINSTANCE_r23 741 +#define _GUARD_CALLABLE_ISINSTANCE_r33 742 +#define _GUARD_CALLABLE_LEN_r03 743 +#define _GUARD_CALLABLE_LEN_r13 744 +#define _GUARD_CALLABLE_LEN_r23 745 +#define _GUARD_CALLABLE_LEN_r33 746 +#define _GUARD_CALLABLE_LIST_APPEND_r03 747 +#define _GUARD_CALLABLE_LIST_APPEND_r13 748 +#define _GUARD_CALLABLE_LIST_APPEND_r23 749 +#define _GUARD_CALLABLE_LIST_APPEND_r33 750 +#define _GUARD_CALLABLE_STR_1_r03 751 +#define _GUARD_CALLABLE_STR_1_r13 752 +#define _GUARD_CALLABLE_STR_1_r23 753 +#define _GUARD_CALLABLE_STR_1_r33 754 +#define _GUARD_CALLABLE_TUPLE_1_r03 755 +#define _GUARD_CALLABLE_TUPLE_1_r13 756 +#define _GUARD_CALLABLE_TUPLE_1_r23 757 +#define _GUARD_CALLABLE_TUPLE_1_r33 758 +#define _GUARD_CALLABLE_TYPE_1_r03 759 +#define _GUARD_CALLABLE_TYPE_1_r13 760 +#define _GUARD_CALLABLE_TYPE_1_r23 761 +#define _GUARD_CALLABLE_TYPE_1_r33 762 +#define _GUARD_DORV_NO_DICT_r01 763 +#define _GUARD_DORV_NO_DICT_r11 764 +#define _GUARD_DORV_NO_DICT_r22 765 +#define _GUARD_DORV_NO_DICT_r33 766 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 767 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 768 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 769 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 770 +#define _GUARD_GLOBALS_VERSION_r00 771 +#define _GUARD_GLOBALS_VERSION_r11 772 +#define _GUARD_GLOBALS_VERSION_r22 773 +#define _GUARD_GLOBALS_VERSION_r33 774 +#define _GUARD_IP_RETURN_GENERATOR_r00 775 +#define _GUARD_IP_RETURN_GENERATOR_r11 776 +#define _GUARD_IP_RETURN_GENERATOR_r22 777 +#define _GUARD_IP_RETURN_GENERATOR_r33 778 +#define _GUARD_IP_RETURN_VALUE_r00 779 +#define _GUARD_IP_RETURN_VALUE_r11 780 +#define _GUARD_IP_RETURN_VALUE_r22 781 +#define _GUARD_IP_RETURN_VALUE_r33 782 +#define _GUARD_IP_YIELD_VALUE_r00 783 +#define _GUARD_IP_YIELD_VALUE_r11 784 +#define _GUARD_IP_YIELD_VALUE_r22 785 +#define _GUARD_IP_YIELD_VALUE_r33 786 +#define _GUARD_IP__PUSH_FRAME_r00 787 +#define _GUARD_IP__PUSH_FRAME_r11 788 +#define _GUARD_IP__PUSH_FRAME_r22 789 +#define _GUARD_IP__PUSH_FRAME_r33 790 +#define _GUARD_IS_FALSE_POP_r00 791 +#define _GUARD_IS_FALSE_POP_r10 792 +#define _GUARD_IS_FALSE_POP_r21 793 +#define _GUARD_IS_FALSE_POP_r32 794 +#define _GUARD_IS_NONE_POP_r00 795 +#define _GUARD_IS_NONE_POP_r10 796 +#define _GUARD_IS_NONE_POP_r21 797 +#define _GUARD_IS_NONE_POP_r32 798 +#define _GUARD_IS_NOT_NONE_POP_r10 799 +#define _GUARD_IS_TRUE_POP_r00 800 +#define _GUARD_IS_TRUE_POP_r10 801 +#define _GUARD_IS_TRUE_POP_r21 802 +#define _GUARD_IS_TRUE_POP_r32 803 +#define _GUARD_KEYS_VERSION_r01 804 +#define _GUARD_KEYS_VERSION_r11 805 +#define _GUARD_KEYS_VERSION_r22 806 +#define _GUARD_KEYS_VERSION_r33 807 +#define _GUARD_NOS_DICT_r02 808 +#define _GUARD_NOS_DICT_r12 809 +#define _GUARD_NOS_DICT_r22 810 +#define _GUARD_NOS_DICT_r33 811 +#define _GUARD_NOS_FLOAT_r02 812 +#define _GUARD_NOS_FLOAT_r12 813 +#define _GUARD_NOS_FLOAT_r22 814 +#define _GUARD_NOS_FLOAT_r33 815 +#define _GUARD_NOS_INT_r02 816 +#define _GUARD_NOS_INT_r12 817 +#define _GUARD_NOS_INT_r22 818 +#define _GUARD_NOS_INT_r33 819 +#define _GUARD_NOS_LIST_r02 820 +#define _GUARD_NOS_LIST_r12 821 +#define _GUARD_NOS_LIST_r22 822 +#define _GUARD_NOS_LIST_r33 823 +#define _GUARD_NOS_NOT_NULL_r02 824 +#define _GUARD_NOS_NOT_NULL_r12 825 +#define _GUARD_NOS_NOT_NULL_r22 826 +#define _GUARD_NOS_NOT_NULL_r33 827 +#define _GUARD_NOS_NULL_r02 828 +#define _GUARD_NOS_NULL_r12 829 +#define _GUARD_NOS_NULL_r22 830 +#define _GUARD_NOS_NULL_r33 831 +#define _GUARD_NOS_OVERFLOWED_r02 832 +#define _GUARD_NOS_OVERFLOWED_r12 833 +#define _GUARD_NOS_OVERFLOWED_r22 834 +#define _GUARD_NOS_OVERFLOWED_r33 835 +#define _GUARD_NOS_TUPLE_r02 836 +#define _GUARD_NOS_TUPLE_r12 837 +#define _GUARD_NOS_TUPLE_r22 838 +#define _GUARD_NOS_TUPLE_r33 839 +#define _GUARD_NOS_UNICODE_r02 840 +#define _GUARD_NOS_UNICODE_r12 841 +#define _GUARD_NOS_UNICODE_r22 842 +#define _GUARD_NOS_UNICODE_r33 843 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 844 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 845 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 846 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 847 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 848 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 849 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 850 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 851 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 852 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 853 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 854 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 855 +#define _GUARD_THIRD_NULL_r03 856 +#define _GUARD_THIRD_NULL_r13 857 +#define _GUARD_THIRD_NULL_r23 858 +#define _GUARD_THIRD_NULL_r33 859 +#define _GUARD_TOS_ANY_SET_r01 860 +#define _GUARD_TOS_ANY_SET_r11 861 +#define _GUARD_TOS_ANY_SET_r22 862 +#define _GUARD_TOS_ANY_SET_r33 863 +#define _GUARD_TOS_DICT_r01 864 +#define _GUARD_TOS_DICT_r11 865 +#define _GUARD_TOS_DICT_r22 866 +#define _GUARD_TOS_DICT_r33 867 +#define _GUARD_TOS_FLOAT_r01 868 +#define _GUARD_TOS_FLOAT_r11 869 +#define _GUARD_TOS_FLOAT_r22 870 +#define _GUARD_TOS_FLOAT_r33 871 +#define _GUARD_TOS_INT_r01 872 +#define _GUARD_TOS_INT_r11 873 +#define _GUARD_TOS_INT_r22 874 +#define _GUARD_TOS_INT_r33 875 +#define _GUARD_TOS_LIST_r01 876 +#define _GUARD_TOS_LIST_r11 877 +#define _GUARD_TOS_LIST_r22 878 +#define _GUARD_TOS_LIST_r33 879 +#define _GUARD_TOS_OVERFLOWED_r01 880 +#define _GUARD_TOS_OVERFLOWED_r11 881 +#define _GUARD_TOS_OVERFLOWED_r22 882 +#define _GUARD_TOS_OVERFLOWED_r33 883 +#define _GUARD_TOS_SLICE_r01 884 +#define _GUARD_TOS_SLICE_r11 885 +#define _GUARD_TOS_SLICE_r22 886 +#define _GUARD_TOS_SLICE_r33 887 +#define _GUARD_TOS_TUPLE_r01 888 +#define _GUARD_TOS_TUPLE_r11 889 +#define _GUARD_TOS_TUPLE_r22 890 +#define _GUARD_TOS_TUPLE_r33 891 +#define _GUARD_TOS_UNICODE_r01 892 +#define _GUARD_TOS_UNICODE_r11 893 +#define _GUARD_TOS_UNICODE_r22 894 +#define _GUARD_TOS_UNICODE_r33 895 +#define _GUARD_TYPE_VERSION_r01 896 +#define _GUARD_TYPE_VERSION_r11 897 +#define _GUARD_TYPE_VERSION_r22 898 +#define _GUARD_TYPE_VERSION_r33 899 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 900 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 901 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 902 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 903 +#define _HANDLE_PENDING_AND_DEOPT_r00 904 +#define _HANDLE_PENDING_AND_DEOPT_r10 905 +#define _HANDLE_PENDING_AND_DEOPT_r20 906 +#define _HANDLE_PENDING_AND_DEOPT_r30 907 +#define _IMPORT_FROM_r12 908 +#define _IMPORT_NAME_r21 909 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 910 +#define _INIT_CALL_PY_EXACT_ARGS_r01 911 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 912 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 913 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 914 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 915 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 916 +#define _INSERT_NULL_r10 917 +#define _INSTRUMENTED_FOR_ITER_r23 918 +#define _INSTRUMENTED_INSTRUCTION_r00 919 +#define _INSTRUMENTED_JUMP_FORWARD_r00 920 +#define _INSTRUMENTED_JUMP_FORWARD_r11 921 +#define _INSTRUMENTED_JUMP_FORWARD_r22 922 +#define _INSTRUMENTED_JUMP_FORWARD_r33 923 +#define _INSTRUMENTED_LINE_r00 924 +#define _INSTRUMENTED_NOT_TAKEN_r00 925 +#define _INSTRUMENTED_NOT_TAKEN_r11 926 +#define _INSTRUMENTED_NOT_TAKEN_r22 927 +#define _INSTRUMENTED_NOT_TAKEN_r33 928 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 929 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 930 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 931 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 932 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 933 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 934 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 935 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 936 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 937 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 938 +#define _IS_NONE_r11 939 +#define _IS_OP_r21 940 +#define _ITER_CHECK_LIST_r02 941 +#define _ITER_CHECK_LIST_r12 942 +#define _ITER_CHECK_LIST_r22 943 +#define _ITER_CHECK_LIST_r33 944 +#define _ITER_CHECK_RANGE_r02 945 +#define _ITER_CHECK_RANGE_r12 946 +#define _ITER_CHECK_RANGE_r22 947 +#define _ITER_CHECK_RANGE_r33 948 +#define _ITER_CHECK_TUPLE_r02 949 +#define _ITER_CHECK_TUPLE_r12 950 +#define _ITER_CHECK_TUPLE_r22 951 +#define _ITER_CHECK_TUPLE_r33 952 +#define _ITER_JUMP_LIST_r02 953 +#define _ITER_JUMP_LIST_r12 954 +#define _ITER_JUMP_LIST_r22 955 +#define _ITER_JUMP_LIST_r33 956 +#define _ITER_JUMP_RANGE_r02 957 +#define _ITER_JUMP_RANGE_r12 958 +#define _ITER_JUMP_RANGE_r22 959 +#define _ITER_JUMP_RANGE_r33 960 +#define _ITER_JUMP_TUPLE_r02 961 +#define _ITER_JUMP_TUPLE_r12 962 +#define _ITER_JUMP_TUPLE_r22 963 +#define _ITER_JUMP_TUPLE_r33 964 +#define _ITER_NEXT_LIST_r23 965 +#define _ITER_NEXT_LIST_TIER_TWO_r23 966 +#define _ITER_NEXT_RANGE_r03 967 +#define _ITER_NEXT_RANGE_r13 968 +#define _ITER_NEXT_RANGE_r23 969 +#define _ITER_NEXT_TUPLE_r03 970 +#define _ITER_NEXT_TUPLE_r13 971 +#define _ITER_NEXT_TUPLE_r23 972 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 973 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 974 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 975 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 976 +#define _JUMP_TO_TOP_r00 977 +#define _LIST_APPEND_r10 978 +#define _LIST_EXTEND_r10 979 +#define _LOAD_ATTR_r10 980 +#define _LOAD_ATTR_CLASS_r11 981 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 982 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 983 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 984 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 985 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 986 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 987 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 988 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 989 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 990 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 991 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 992 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 993 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 994 +#define _LOAD_ATTR_MODULE_r11 995 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 996 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 997 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 998 +#define _LOAD_ATTR_SLOT_r11 999 +#define _LOAD_ATTR_WITH_HINT_r11 1000 +#define _LOAD_BUILD_CLASS_r01 1001 +#define _LOAD_BYTECODE_r00 1002 +#define _LOAD_COMMON_CONSTANT_r01 1003 +#define _LOAD_COMMON_CONSTANT_r12 1004 +#define _LOAD_COMMON_CONSTANT_r23 1005 +#define _LOAD_CONST_r01 1006 +#define _LOAD_CONST_r12 1007 +#define _LOAD_CONST_r23 1008 +#define _LOAD_CONST_INLINE_r01 1009 +#define _LOAD_CONST_INLINE_r12 1010 +#define _LOAD_CONST_INLINE_r23 1011 +#define _LOAD_CONST_INLINE_BORROW_r01 1012 +#define _LOAD_CONST_INLINE_BORROW_r12 1013 +#define _LOAD_CONST_INLINE_BORROW_r23 1014 +#define _LOAD_CONST_UNDER_INLINE_r02 1015 +#define _LOAD_CONST_UNDER_INLINE_r12 1016 +#define _LOAD_CONST_UNDER_INLINE_r23 1017 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1018 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1019 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1020 +#define _LOAD_DEREF_r01 1021 +#define _LOAD_FAST_r01 1022 +#define _LOAD_FAST_r12 1023 +#define _LOAD_FAST_r23 1024 +#define _LOAD_FAST_0_r01 1025 +#define _LOAD_FAST_0_r12 1026 +#define _LOAD_FAST_0_r23 1027 +#define _LOAD_FAST_1_r01 1028 +#define _LOAD_FAST_1_r12 1029 +#define _LOAD_FAST_1_r23 1030 +#define _LOAD_FAST_2_r01 1031 +#define _LOAD_FAST_2_r12 1032 +#define _LOAD_FAST_2_r23 1033 +#define _LOAD_FAST_3_r01 1034 +#define _LOAD_FAST_3_r12 1035 +#define _LOAD_FAST_3_r23 1036 +#define _LOAD_FAST_4_r01 1037 +#define _LOAD_FAST_4_r12 1038 +#define _LOAD_FAST_4_r23 1039 +#define _LOAD_FAST_5_r01 1040 +#define _LOAD_FAST_5_r12 1041 +#define _LOAD_FAST_5_r23 1042 +#define _LOAD_FAST_6_r01 1043 +#define _LOAD_FAST_6_r12 1044 +#define _LOAD_FAST_6_r23 1045 +#define _LOAD_FAST_7_r01 1046 +#define _LOAD_FAST_7_r12 1047 +#define _LOAD_FAST_7_r23 1048 +#define _LOAD_FAST_AND_CLEAR_r01 1049 +#define _LOAD_FAST_AND_CLEAR_r12 1050 +#define _LOAD_FAST_AND_CLEAR_r23 1051 +#define _LOAD_FAST_BORROW_r01 1052 +#define _LOAD_FAST_BORROW_r12 1053 +#define _LOAD_FAST_BORROW_r23 1054 +#define _LOAD_FAST_BORROW_0_r01 1055 +#define _LOAD_FAST_BORROW_0_r12 1056 +#define _LOAD_FAST_BORROW_0_r23 1057 +#define _LOAD_FAST_BORROW_1_r01 1058 +#define _LOAD_FAST_BORROW_1_r12 1059 +#define _LOAD_FAST_BORROW_1_r23 1060 +#define _LOAD_FAST_BORROW_2_r01 1061 +#define _LOAD_FAST_BORROW_2_r12 1062 +#define _LOAD_FAST_BORROW_2_r23 1063 +#define _LOAD_FAST_BORROW_3_r01 1064 +#define _LOAD_FAST_BORROW_3_r12 1065 +#define _LOAD_FAST_BORROW_3_r23 1066 +#define _LOAD_FAST_BORROW_4_r01 1067 +#define _LOAD_FAST_BORROW_4_r12 1068 +#define _LOAD_FAST_BORROW_4_r23 1069 +#define _LOAD_FAST_BORROW_5_r01 1070 +#define _LOAD_FAST_BORROW_5_r12 1071 +#define _LOAD_FAST_BORROW_5_r23 1072 +#define _LOAD_FAST_BORROW_6_r01 1073 +#define _LOAD_FAST_BORROW_6_r12 1074 +#define _LOAD_FAST_BORROW_6_r23 1075 +#define _LOAD_FAST_BORROW_7_r01 1076 +#define _LOAD_FAST_BORROW_7_r12 1077 +#define _LOAD_FAST_BORROW_7_r23 1078 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1079 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1080 +#define _LOAD_FAST_CHECK_r01 1081 +#define _LOAD_FAST_CHECK_r12 1082 +#define _LOAD_FAST_CHECK_r23 1083 +#define _LOAD_FAST_LOAD_FAST_r02 1084 +#define _LOAD_FAST_LOAD_FAST_r13 1085 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1086 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1087 +#define _LOAD_GLOBAL_r00 1088 +#define _LOAD_GLOBAL_BUILTINS_r01 1089 +#define _LOAD_GLOBAL_MODULE_r01 1090 +#define _LOAD_LOCALS_r01 1091 +#define _LOAD_LOCALS_r12 1092 +#define _LOAD_LOCALS_r23 1093 +#define _LOAD_NAME_r01 1094 +#define _LOAD_SMALL_INT_r01 1095 +#define _LOAD_SMALL_INT_r12 1096 +#define _LOAD_SMALL_INT_r23 1097 +#define _LOAD_SMALL_INT_0_r01 1098 +#define _LOAD_SMALL_INT_0_r12 1099 +#define _LOAD_SMALL_INT_0_r23 1100 +#define _LOAD_SMALL_INT_1_r01 1101 +#define _LOAD_SMALL_INT_1_r12 1102 +#define _LOAD_SMALL_INT_1_r23 1103 +#define _LOAD_SMALL_INT_2_r01 1104 +#define _LOAD_SMALL_INT_2_r12 1105 +#define _LOAD_SMALL_INT_2_r23 1106 +#define _LOAD_SMALL_INT_3_r01 1107 +#define _LOAD_SMALL_INT_3_r12 1108 +#define _LOAD_SMALL_INT_3_r23 1109 +#define _LOAD_SPECIAL_r00 1110 +#define _LOAD_SUPER_ATTR_ATTR_r31 1111 +#define _LOAD_SUPER_ATTR_METHOD_r32 1112 +#define _MAKE_CALLARGS_A_TUPLE_r33 1113 +#define _MAKE_CELL_r00 1114 +#define _MAKE_FUNCTION_r11 1115 +#define _MAKE_WARM_r00 1116 +#define _MAKE_WARM_r11 1117 +#define _MAKE_WARM_r22 1118 +#define _MAKE_WARM_r33 1119 +#define _MAP_ADD_r20 1120 +#define _MATCH_CLASS_r31 1121 +#define _MATCH_KEYS_r23 1122 +#define _MATCH_MAPPING_r02 1123 +#define _MATCH_MAPPING_r12 1124 +#define _MATCH_MAPPING_r23 1125 +#define _MATCH_SEQUENCE_r02 1126 +#define _MATCH_SEQUENCE_r12 1127 +#define _MATCH_SEQUENCE_r23 1128 +#define _MAYBE_EXPAND_METHOD_r00 1129 +#define _MAYBE_EXPAND_METHOD_KW_r11 1130 +#define _MONITOR_CALL_r00 1131 +#define _MONITOR_CALL_KW_r11 1132 +#define _MONITOR_JUMP_BACKWARD_r00 1133 +#define _MONITOR_JUMP_BACKWARD_r11 1134 +#define _MONITOR_JUMP_BACKWARD_r22 1135 +#define _MONITOR_JUMP_BACKWARD_r33 1136 +#define _MONITOR_RESUME_r00 1137 +#define _NOP_r00 1138 +#define _NOP_r11 1139 +#define _NOP_r22 1140 +#define _NOP_r33 1141 +#define _POP_CALL_r20 1142 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1143 +#define _POP_CALL_ONE_r30 1144 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1145 +#define _POP_CALL_TWO_r30 1146 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1147 +#define _POP_EXCEPT_r10 1148 +#define _POP_ITER_r20 1149 +#define _POP_JUMP_IF_FALSE_r00 1150 +#define _POP_JUMP_IF_FALSE_r10 1151 +#define _POP_JUMP_IF_FALSE_r21 1152 +#define _POP_JUMP_IF_FALSE_r32 1153 +#define _POP_JUMP_IF_TRUE_r00 1154 +#define _POP_JUMP_IF_TRUE_r10 1155 +#define _POP_JUMP_IF_TRUE_r21 1156 +#define _POP_JUMP_IF_TRUE_r32 1157 +#define _POP_TOP_r10 1158 +#define _POP_TOP_FLOAT_r00 1159 +#define _POP_TOP_FLOAT_r10 1160 +#define _POP_TOP_FLOAT_r21 1161 +#define _POP_TOP_FLOAT_r32 1162 +#define _POP_TOP_INT_r00 1163 +#define _POP_TOP_INT_r10 1164 +#define _POP_TOP_INT_r21 1165 +#define _POP_TOP_INT_r32 1166 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1167 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1168 +#define _POP_TOP_NOP_r00 1169 +#define _POP_TOP_NOP_r10 1170 +#define _POP_TOP_NOP_r21 1171 +#define _POP_TOP_NOP_r32 1172 +#define _POP_TOP_UNICODE_r00 1173 +#define _POP_TOP_UNICODE_r10 1174 +#define _POP_TOP_UNICODE_r21 1175 +#define _POP_TOP_UNICODE_r32 1176 +#define _POP_TWO_r20 1177 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1178 +#define _PUSH_EXC_INFO_r02 1179 +#define _PUSH_EXC_INFO_r12 1180 +#define _PUSH_EXC_INFO_r23 1181 +#define _PUSH_FRAME_r10 1182 +#define _PUSH_NULL_r01 1183 +#define _PUSH_NULL_r12 1184 +#define _PUSH_NULL_r23 1185 +#define _PUSH_NULL_CONDITIONAL_r00 1186 +#define _PY_FRAME_GENERAL_r01 1187 +#define _PY_FRAME_KW_r11 1188 +#define _QUICKEN_RESUME_r00 1189 +#define _QUICKEN_RESUME_r11 1190 +#define _QUICKEN_RESUME_r22 1191 +#define _QUICKEN_RESUME_r33 1192 +#define _REPLACE_WITH_TRUE_r11 1193 +#define _RESUME_CHECK_r00 1194 +#define _RESUME_CHECK_r11 1195 +#define _RESUME_CHECK_r22 1196 +#define _RESUME_CHECK_r33 1197 +#define _RETURN_GENERATOR_r01 1198 +#define _RETURN_VALUE_r11 1199 +#define _SAVE_RETURN_OFFSET_r00 1200 +#define _SAVE_RETURN_OFFSET_r11 1201 +#define _SAVE_RETURN_OFFSET_r22 1202 +#define _SAVE_RETURN_OFFSET_r33 1203 +#define _SEND_r22 1204 +#define _SEND_GEN_FRAME_r22 1205 +#define _SETUP_ANNOTATIONS_r00 1206 +#define _SET_ADD_r10 1207 +#define _SET_FUNCTION_ATTRIBUTE_r01 1208 +#define _SET_FUNCTION_ATTRIBUTE_r11 1209 +#define _SET_FUNCTION_ATTRIBUTE_r21 1210 +#define _SET_FUNCTION_ATTRIBUTE_r32 1211 +#define _SET_IP_r00 1212 +#define _SET_IP_r11 1213 +#define _SET_IP_r22 1214 +#define _SET_IP_r33 1215 +#define _SET_UPDATE_r10 1216 +#define _SPILL_OR_RELOAD_r01 1217 +#define _SPILL_OR_RELOAD_r02 1218 +#define _SPILL_OR_RELOAD_r03 1219 +#define _SPILL_OR_RELOAD_r10 1220 +#define _SPILL_OR_RELOAD_r12 1221 +#define _SPILL_OR_RELOAD_r13 1222 +#define _SPILL_OR_RELOAD_r20 1223 +#define _SPILL_OR_RELOAD_r21 1224 +#define _SPILL_OR_RELOAD_r23 1225 +#define _SPILL_OR_RELOAD_r30 1226 +#define _SPILL_OR_RELOAD_r31 1227 +#define _SPILL_OR_RELOAD_r32 1228 +#define _START_EXECUTOR_r00 1229 +#define _STORE_ATTR_r20 1230 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1231 +#define _STORE_ATTR_SLOT_r21 1232 +#define _STORE_ATTR_WITH_HINT_r21 1233 +#define _STORE_DEREF_r10 1234 +#define _STORE_FAST_r10 1235 +#define _STORE_FAST_0_r10 1236 +#define _STORE_FAST_1_r10 1237 +#define _STORE_FAST_2_r10 1238 +#define _STORE_FAST_3_r10 1239 +#define _STORE_FAST_4_r10 1240 +#define _STORE_FAST_5_r10 1241 +#define _STORE_FAST_6_r10 1242 +#define _STORE_FAST_7_r10 1243 +#define _STORE_FAST_LOAD_FAST_r11 1244 +#define _STORE_FAST_STORE_FAST_r20 1245 +#define _STORE_GLOBAL_r10 1246 +#define _STORE_NAME_r10 1247 +#define _STORE_SLICE_r30 1248 +#define _STORE_SUBSCR_r30 1249 +#define _STORE_SUBSCR_DICT_r31 1250 +#define _STORE_SUBSCR_LIST_INT_r32 1251 +#define _SWAP_r11 1252 +#define _SWAP_2_r02 1253 +#define _SWAP_2_r12 1254 +#define _SWAP_2_r22 1255 +#define _SWAP_2_r33 1256 +#define _SWAP_3_r03 1257 +#define _SWAP_3_r13 1258 +#define _SWAP_3_r23 1259 +#define _SWAP_3_r33 1260 +#define _TIER2_RESUME_CHECK_r00 1261 +#define _TIER2_RESUME_CHECK_r11 1262 +#define _TIER2_RESUME_CHECK_r22 1263 +#define _TIER2_RESUME_CHECK_r33 1264 +#define _TO_BOOL_r11 1265 +#define _TO_BOOL_BOOL_r01 1266 +#define _TO_BOOL_BOOL_r11 1267 +#define _TO_BOOL_BOOL_r22 1268 +#define _TO_BOOL_BOOL_r33 1269 +#define _TO_BOOL_INT_r11 1270 +#define _TO_BOOL_LIST_r11 1271 +#define _TO_BOOL_NONE_r01 1272 +#define _TO_BOOL_NONE_r11 1273 +#define _TO_BOOL_NONE_r22 1274 +#define _TO_BOOL_NONE_r33 1275 +#define _TO_BOOL_STR_r11 1276 +#define _TRACE_RECORD_r00 1277 +#define _UNARY_INVERT_r11 1278 +#define _UNARY_NEGATIVE_r11 1279 +#define _UNARY_NOT_r01 1280 +#define _UNARY_NOT_r11 1281 +#define _UNARY_NOT_r22 1282 +#define _UNARY_NOT_r33 1283 +#define _UNPACK_EX_r10 1284 +#define _UNPACK_SEQUENCE_r10 1285 +#define _UNPACK_SEQUENCE_LIST_r10 1286 +#define _UNPACK_SEQUENCE_TUPLE_r10 1287 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1288 +#define _WITH_EXCEPT_START_r33 1289 +#define _YIELD_VALUE_r11 1290 +#define MAX_UOP_REGS_ID 1290 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index c6d3670b193123..0cc38919565bc1 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -111,7 +111,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_BINARY_OP_MULTIPLY_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, [_BINARY_OP_ADD_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, [_BINARY_OP_SUBTRACT_FLOAT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, - [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_PURE_FLAG, + [_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG, [_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG, @@ -1050,12 +1050,12 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { }, }, [_BINARY_OP_ADD_UNICODE] = { - .best = { 0, 1, 2, 3 }, + .best = { 0, 1, 2, 2 }, .entries = { - { 1, 0, _BINARY_OP_ADD_UNICODE_r01 }, - { 1, 1, _BINARY_OP_ADD_UNICODE_r11 }, - { 1, 2, _BINARY_OP_ADD_UNICODE_r21 }, - { 2, 3, _BINARY_OP_ADD_UNICODE_r32 }, + { 3, 0, _BINARY_OP_ADD_UNICODE_r03 }, + { 3, 1, _BINARY_OP_ADD_UNICODE_r13 }, + { 3, 2, _BINARY_OP_ADD_UNICODE_r23 }, + { -1, -1, -1 }, }, }, [_BINARY_OP_INPLACE_ADD_UNICODE] = { @@ -3414,10 +3414,9 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_SUBTRACT_FLOAT_r03] = _BINARY_OP_SUBTRACT_FLOAT, [_BINARY_OP_SUBTRACT_FLOAT_r13] = _BINARY_OP_SUBTRACT_FLOAT, [_BINARY_OP_SUBTRACT_FLOAT_r23] = _BINARY_OP_SUBTRACT_FLOAT, - [_BINARY_OP_ADD_UNICODE_r01] = _BINARY_OP_ADD_UNICODE, - [_BINARY_OP_ADD_UNICODE_r11] = _BINARY_OP_ADD_UNICODE, - [_BINARY_OP_ADD_UNICODE_r21] = _BINARY_OP_ADD_UNICODE, - [_BINARY_OP_ADD_UNICODE_r32] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_ADD_UNICODE_r03] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_ADD_UNICODE_r13] = _BINARY_OP_ADD_UNICODE, + [_BINARY_OP_ADD_UNICODE_r23] = _BINARY_OP_ADD_UNICODE, [_BINARY_OP_INPLACE_ADD_UNICODE_r20] = _BINARY_OP_INPLACE_ADD_UNICODE, [_GUARD_BINARY_OP_EXTEND_r22] = _GUARD_BINARY_OP_EXTEND, [_BINARY_OP_EXTEND_r21] = _BINARY_OP_EXTEND, @@ -3906,10 +3905,9 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_ADD_INT_r13] = "_BINARY_OP_ADD_INT_r13", [_BINARY_OP_ADD_INT_r23] = "_BINARY_OP_ADD_INT_r23", [_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE", - [_BINARY_OP_ADD_UNICODE_r01] = "_BINARY_OP_ADD_UNICODE_r01", - [_BINARY_OP_ADD_UNICODE_r11] = "_BINARY_OP_ADD_UNICODE_r11", - [_BINARY_OP_ADD_UNICODE_r21] = "_BINARY_OP_ADD_UNICODE_r21", - [_BINARY_OP_ADD_UNICODE_r32] = "_BINARY_OP_ADD_UNICODE_r32", + [_BINARY_OP_ADD_UNICODE_r03] = "_BINARY_OP_ADD_UNICODE_r03", + [_BINARY_OP_ADD_UNICODE_r13] = "_BINARY_OP_ADD_UNICODE_r13", + [_BINARY_OP_ADD_UNICODE_r23] = "_BINARY_OP_ADD_UNICODE_r23", [_BINARY_OP_EXTEND] = "_BINARY_OP_EXTEND", [_BINARY_OP_EXTEND_r21] = "_BINARY_OP_EXTEND_r21", [_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index bed8d1d52e93b2..6f1b115b31257f 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2552,6 +2552,22 @@ def testfunc(n): self.assertIn("_POP_TOP_NOP", uops) self.assertNotIn("_POP_TOP", uops) + def test_unicode_add_op_refcount_elimination(self): + def testfunc(n): + c = "a" + res = "" + for _ in range(n): + res = c + c + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, "aa") + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_ADD_UNICODE", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + def test_remove_guard_for_slice_list(self): def f(n): for i in range(n): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 25e730f7e6e8ec..07944f624ede95 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -742,7 +742,7 @@ dummy_func( macro(BINARY_OP_SUBTRACT_FLOAT) = _GUARD_TOS_FLOAT + _GUARD_NOS_FLOAT + unused/5 + _BINARY_OP_SUBTRACT_FLOAT + _POP_TOP_FLOAT + _POP_TOP_FLOAT; - pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { + pure op(_BINARY_OP_ADD_UNICODE, (left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(PyUnicode_CheckExact(left_o)); @@ -750,15 +750,17 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - INPUTS_DEAD(); - ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + ERROR_NO_POP(); + } + l = left; + r = right; + INPUTS_DEAD(); } macro(BINARY_OP_ADD_UNICODE) = - _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE; + _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_ADD_UNICODE + _POP_TOP_UNICODE + _POP_TOP_UNICODE; // This is a subtle one. It's a super-instruction for // BINARY_OP_ADD_UNICODE followed by STORE_FAST diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 55c4495f2dc59d..9f3a207929ff9f 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4184,12 +4184,14 @@ break; } - case _BINARY_OP_ADD_UNICODE_r01: { + case _BINARY_OP_ADD_UNICODE_r03: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); @@ -4198,29 +4200,31 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - res = PyStackRef_FromPyObjectSteal(res_o); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; _tos_cache0 = res; - SET_CURRENT_CACHED_VALUES(1); + SET_CURRENT_CACHED_VALUES(3); stack_pointer += -2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_UNICODE_r11: { + case _BINARY_OP_ADD_UNICODE_r13: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; _PyStackRef _stack_item_0 = _tos_cache0; right = _stack_item_0; left = stack_pointer[-1]; @@ -4230,29 +4234,34 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - stack_pointer += -1; + res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = right; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - res = PyStackRef_FromPyObjectSteal(res_o); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; _tos_cache0 = res; - SET_CURRENT_CACHED_VALUES(1); + SET_CURRENT_CACHED_VALUES(3); stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } - case _BINARY_OP_ADD_UNICODE_r21: { + case _BINARY_OP_ADD_UNICODE_r23: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef right; _PyStackRef left; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; right = _stack_item_1; @@ -4263,49 +4272,21 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_ERROR(); - } res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache0 = res; - SET_CURRENT_CACHED_VALUES(1); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _BINARY_OP_ADD_UNICODE_r32: { - CHECK_CURRENT_CACHED_VALUES(3); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef right; - _PyStackRef left; - _PyStackRef res; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - _PyStackRef _stack_item_2 = _tos_cache2; - right = _stack_item_2; - left = _stack_item_1; - PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - assert(PyUnicode_CheckExact(left_o)); - assert(PyUnicode_CheckExact(right_o)); - STAT_INC(BINARY_OP, hit); - PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - stack_pointer[0] = _stack_item_0; - stack_pointer += 1; + if (PyStackRef_IsNull(res)) { + stack_pointer[0] = left; + stack_pointer[1] = right; + stack_pointer += 2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache1 = res; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); + l = left; + r = right; + _tos_cache2 = r; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 3c18960a39d7d7..8d3119e9169d19 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -245,6 +245,8 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; // _GUARD_TOS_UNICODE { value = stack_pointer[-1]; @@ -276,12 +278,24 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - JUMP_TO_LABEL(pop_2_error); - } res = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + JUMP_TO_LABEL(error); + } + l = left; + r = right; + } + // _POP_TOP_UNICODE + { + value = r; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); + } + // _POP_TOP_UNICODE + { + value = l; + assert(PyUnicode_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyUnicode_ExactDealloc); } stack_pointer[-2] = res; stack_pointer += -1; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 31ec88e1c84912..e3921054f7cb43 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -298,12 +298,14 @@ dummy_func(void) { r = right; } - op(_BINARY_OP_ADD_UNICODE, (left, right -- res)) { + op(_BINARY_OP_ADD_UNICODE, (left, right -- res, l, r)) { REPLACE_OPCODE_IF_EVALUATES_PURE(left, right); res = sym_new_type(ctx, &PyUnicode_Type); + l = left; + r = right; } - op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- )) { + op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) { JitOptRef res; if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { assert(PyUnicode_CheckExact(sym_get_const(ctx, left))); @@ -563,6 +565,12 @@ dummy_func(void) { } } + op(_POP_TOP_UNICODE, (value --)) { + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } + } + op(_COPY, (bottom, unused[oparg-1] -- bottom, unused[oparg-1], top)) { assert(oparg > 0); top = bottom; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 6fde87a17fbaa3..32d60c76a4f3ce 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -165,6 +165,11 @@ } case _POP_TOP_UNICODE: { + JitOptRef value; + value = stack_pointer[-1]; + if (PyJitRef_IsBorrowed(value)) { + REPLACE_OP(this_instr, _POP_TOP_NOP, 0, 0); + } CHECK_STACK_BOUNDS(-1); stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -637,6 +642,8 @@ JitOptRef right; JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; if ( @@ -648,6 +655,8 @@ _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym); _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym); _PyStackRef res_stackref; + _PyStackRef l_stackref; + _PyStackRef r_stackref; /* Start of uop copied from bytecodes for constant evaluation */ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); @@ -655,31 +664,32 @@ assert(PyUnicode_CheckExact(right_o)); STAT_INC(BINARY_OP, hit); PyObject *res_o = PyUnicode_Concat(left_o, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); - if (res_o == NULL) { - goto error; - } res_stackref = PyStackRef_FromPyObjectSteal(res_o); + if (PyStackRef_IsNull(res)) { + JUMP_TO_LABEL(error); + } + l_stackref = left; + r_stackref = right; /* End of uop copied from bytecodes for constant evaluation */ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref)); - if (sym_is_const(ctx, res)) { - PyObject *result = sym_get_const(ctx, res); - if (_Py_IsImmortal(result)) { - // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result - REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); - } - } - CHECK_STACK_BOUNDS(-1); + l = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(l_stackref)); + r = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(r_stackref)); + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } res = sym_new_type(ctx, &PyUnicode_Type); - CHECK_STACK_BOUNDS(-1); + l = left; + r = right; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[-1] = l; + stack_pointer[0] = r; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } From 1c544acaa5a83d72839b546af99f8a051437f51f Mon Sep 17 00:00:00 2001 From: MonadChains Date: Thu, 18 Dec 2025 13:50:05 +0100 Subject: [PATCH 005/105] gh-124098: Fix incorrect inclusion of handler methods without protocol prefix in OpenerDirector (GH-136873) --- Lib/test/test_urllib2.py | 17 +++++++++++++++++ Lib/urllib/request.py | 2 ++ ...25-07-20-15-39-54.gh-issue-124098.znFPIp.rst | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py index 7d7f2fa00d35b6..3a77b9e5ab7928 100644 --- a/Lib/test/test_urllib2.py +++ b/Lib/test/test_urllib2.py @@ -577,6 +577,23 @@ class NonHandler(object): self.assertRaises(TypeError, OpenerDirector().add_handler, NonHandler()) + def test_no_protocol_methods(self): + # test the case that methods starts with handler type without the protocol + # like open*() or _open*(). + # These methods should be ignored + + o = OpenerDirector() + meth_spec = [ + ["open"], + ["_open"], + ["error"] + ] + + add_ordered_mock_handlers(o, meth_spec) + + self.assertEqual(len(o.handle_open), 0) + self.assertEqual(len(o.handle_error), 0) + def test_badly_named_methods(self): # test work-around for three methods that accidentally follow the # naming conventions for handler methods diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 566b8087aec277..f32de189b1353a 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -415,6 +415,8 @@ def add_handler(self, handler): continue i = meth.find("_") + if i < 1: + continue protocol = meth[:i] condition = meth[i+1:] diff --git a/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst b/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst new file mode 100644 index 00000000000000..236b37d268ef2d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-20-15-39-54.gh-issue-124098.znFPIp.rst @@ -0,0 +1,4 @@ +Fix issue where methods in handlers that lacked the protocol name but +matched a valid base handler method (e.g., ``_open()`` or ``error()``) +were incorrectly added to :class:`urllib.request.OpenerDirector`'s +handlers. Contributed by Andrea Mattei. From ddfc155d3ade5f4867c6789136df73f61d4efb03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Thu, 18 Dec 2025 14:00:12 +0100 Subject: [PATCH 006/105] gh-142784: make the asyncio REPL call `loop.close()` at exit (#142785) --- Lib/asyncio/__main__.py | 1 + .../Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index d078ebfa4cedbe..89d456b6858c07 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -240,4 +240,5 @@ def interrupt(self) -> None: break console.write('exiting asyncio REPL...\n') + loop.close() sys.exit(return_code) diff --git a/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst new file mode 100644 index 00000000000000..92a723cbc29739 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-04-39-27.gh-issue-142784.HBGJag.rst @@ -0,0 +1,3 @@ +The :mod:`asyncio` REPL now properly closes the loop upon the end of interactive session. +Previously, it could cause surprising warnings. +Contributed by Bartosz Sławecki. From 0f01530bd5a12639287b329050a143e442b23061 Mon Sep 17 00:00:00 2001 From: Max R Date: Thu, 18 Dec 2025 08:43:19 -0500 Subject: [PATCH 007/105] Fix typo in `format_string` docstring (GH-136742) --- Lib/locale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/locale.py b/Lib/locale.py index 37cafb4a601b3c..0f1b429ea419b0 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -214,7 +214,7 @@ def format_string(f, val, grouping=False, monetary=False): Grouping is applied if the third parameter is true. Conversion uses monetary thousands separator and grouping strings if - forth parameter monetary is true.""" + fourth parameter monetary is true.""" global _percent_re if _percent_re is None: import re From d2abd5733b2dc478abb848230d7e8374e74a6927 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:22:23 +0200 Subject: [PATCH 008/105] gh-76007: Deprecate `VERSION` in `xml.etree.ElementTree` & `version` in `xml.sax.expatreader` & `xml.sax.handler` (#142898) --- Doc/deprecations/pending-removal-in-3.20.rst | 9 ++++++--- Doc/whatsnew/3.15.rst | 9 ++++++--- Lib/test/test_sax.py | 12 ++++++++++++ Lib/test/test_xml_etree.py | 13 +++++++++++++ Lib/xml/etree/ElementTree.py | 14 +++++++++++--- Lib/xml/sax/expatreader.py | 12 ++++++++++-- Lib/xml/sax/handler.py | 11 +++++++++-- .../2025-12-16-14-21-20.gh-issue-76007.O4AmYl.rst | 3 +++ 8 files changed, 70 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-16-14-21-20.gh-issue-76007.O4AmYl.rst diff --git a/Doc/deprecations/pending-removal-in-3.20.rst b/Doc/deprecations/pending-removal-in-3.20.rst index 185f20fbc6d125..4e4b2e1d5f8fff 100644 --- a/Doc/deprecations/pending-removal-in-3.20.rst +++ b/Doc/deprecations/pending-removal-in-3.20.rst @@ -1,9 +1,9 @@ Pending removal in Python 3.20 ------------------------------ -* The ``__version__`` attribute has been deprecated in these standard library - modules and will be removed in Python 3.20. - Use :py:data:`sys.version_info` instead. +* The ``__version__``, ``version`` and ``VERSION`` attributes have been + deprecated in these standard library modules and will be removed in + Python 3.20. Use :py:data:`sys.version_info` instead. - :mod:`argparse` - :mod:`csv` @@ -24,6 +24,9 @@ Pending removal in Python 3.20 - :mod:`tkinter.font` - :mod:`tkinter.ttk` - :mod:`wsgiref.simple_server` + - :mod:`xml.etree.ElementTree` + - :mod:`!xml.sax.expatreader` + - :mod:`xml.sax.handler` - :mod:`zlib` (Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 7e032fe5df2fdf..753b1990eb3308 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1104,9 +1104,9 @@ New deprecations * ``__version__`` - * The ``__version__`` attribute has been deprecated in these standard library - modules and will be removed in Python 3.20. - Use :py:data:`sys.version_info` instead. + * The ``__version__``, ``version`` and ``VERSION`` attributes have been + deprecated in these standard library modules and will be removed in + Python 3.20. Use :py:data:`sys.version_info` instead. - :mod:`argparse` - :mod:`csv` @@ -1127,6 +1127,9 @@ New deprecations - :mod:`tkinter.font` - :mod:`tkinter.ttk` - :mod:`wsgiref.simple_server` + - :mod:`xml.etree.ElementTree` + - :mod:`!xml.sax.expatreader` + - :mod:`xml.sax.handler` - :mod:`zlib` (Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.) diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index 5c10bcedc69bc6..29babd7bf6996a 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -1573,5 +1573,17 @@ def test_all(self): check__all__(self, sax, extra=extra) +class TestModule(unittest.TestCase): + def test_deprecated__version__and__date__(self): + for module in (sax.expatreader, sax.handler): + with self.subTest(module=module): + with self.assertWarnsRegex( + DeprecationWarning, + "'version' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(module, "version") + self.assertEqual(cm.filename, __file__) + + if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py index 87811199706a1f..0178ed02b35be1 100644 --- a/Lib/test/test_xml_etree.py +++ b/Lib/test/test_xml_etree.py @@ -4705,6 +4705,19 @@ def get_option(config, option_name, default=None): # -------------------------------------------------------------------- + +class TestModule(unittest.TestCase): + def test_deprecated_version(self): + with self.assertWarnsRegex( + DeprecationWarning, + "'VERSION' is deprecated and slated for removal in Python 3.20", + ) as cm: + getattr(ET, "VERSION") + self.assertEqual(cm.filename, __file__) + + +# -------------------------------------------------------------------- + def setUpModule(module=None): # When invoked without a module, runs the Python ET tests by loading pyET. # Otherwise, uses the given module as the ET. diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index d8c0b1b621684b..92f902b9a8b875 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -83,15 +83,12 @@ "SubElement", "tostring", "tostringlist", "TreeBuilder", - "VERSION", "XML", "XMLID", "XMLParser", "XMLPullParser", "register_namespace", "canonicalize", "C14NWriterTarget", ] -VERSION = "1.3.0" - import sys import re import warnings @@ -2104,3 +2101,14 @@ def _escape_attrib_c14n(text): pass else: _set_factories(Comment, ProcessingInstruction) + + +# -------------------------------------------------------------------- + +def __getattr__(name): + if name == "VERSION": + from warnings import _deprecated + + _deprecated("VERSION", remove=(3, 20)) + return "1.3.0" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Lib/xml/sax/expatreader.py b/Lib/xml/sax/expatreader.py index ba3c1e98517429..37b1add2848487 100644 --- a/Lib/xml/sax/expatreader.py +++ b/Lib/xml/sax/expatreader.py @@ -3,8 +3,6 @@ pyexpat.__version__ == '2.22'. """ -version = "0.20" - from xml.sax._exceptions import * from xml.sax.handler import feature_validation, feature_namespaces from xml.sax.handler import feature_namespace_prefixes @@ -446,6 +444,16 @@ def create_parser(*args, **kwargs): # --- +def __getattr__(name): + if name == "version": + from warnings import _deprecated + + _deprecated("version", remove=(3, 20)) + return "0.20" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + +# --- + if __name__ == "__main__": import xml.sax.saxutils p = create_parser() diff --git a/Lib/xml/sax/handler.py b/Lib/xml/sax/handler.py index 3183c3fe96d74f..9c2e3af838a40f 100644 --- a/Lib/xml/sax/handler.py +++ b/Lib/xml/sax/handler.py @@ -9,8 +9,6 @@ $Id$ """ -version = '2.0beta' - #============================================================================ # # HANDLER INTERFACES @@ -385,3 +383,12 @@ def startCDATA(self): def endCDATA(self): """Reports the end of a CDATA marked section.""" + + +def __getattr__(name): + if name == "version": + from warnings import _deprecated + + _deprecated("version", remove=(3, 20)) + return "2.0beta" # Do not change + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Misc/NEWS.d/next/Library/2025-12-16-14-21-20.gh-issue-76007.O4AmYl.rst b/Misc/NEWS.d/next/Library/2025-12-16-14-21-20.gh-issue-76007.O4AmYl.rst new file mode 100644 index 00000000000000..cfda7327e8fee8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-14-21-20.gh-issue-76007.O4AmYl.rst @@ -0,0 +1,3 @@ +Deprecate ``VERSION`` from :mod:`xml.etree.ElementTree` and ``version`` from +:mod:`!xml.sax.expatreader` and :mod:`xml.sax.handler`. Patch by Hugo van +Kemenade. From 14f0b5191ad1d749d2ba5810f4f4495ee5581ce9 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 18 Dec 2025 23:33:49 +0900 Subject: [PATCH 009/105] gh-142419: Add mmap.set_name method for user custom annotation (gh-142480) --- Doc/library/mmap.rst | 11 +++++ Doc/whatsnew/3.15.rst | 5 ++ Include/internal/pycore_mmap.h | 18 +++---- Lib/test/test_mmap.py | 41 ++++++++++++++++ ...-12-10-02-31-43.gh-issue-142419.C8_LES.rst | 3 ++ Modules/clinic/mmapmodule.c.h | 38 ++++++++++++++- Modules/mmapmodule.c | 48 ++++++++++++++++++- Objects/obmalloc.c | 2 +- Python/jit.c | 2 +- Python/perf_jit_trampoline.c | 3 +- Python/perf_trampoline.c | 2 +- 11 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-10-02-31-43.gh-issue-142419.C8_LES.rst diff --git a/Doc/library/mmap.rst b/Doc/library/mmap.rst index f32aa322c40dbb..41b90f2c3b3111 100644 --- a/Doc/library/mmap.rst +++ b/Doc/library/mmap.rst @@ -328,6 +328,17 @@ To map anonymous memory, -1 should be passed as the fileno along with the length .. versionadded:: 3.13 + .. method:: set_name(name, /) + + Annotate the memory mapping with the given *name* for easier identification + in ``/proc//maps`` if the kernel supports the feature and :option:`-X dev <-X>` is passed + to Python or if Python is built in :ref:`debug mode `. + The length of *name* must not exceed 67 bytes including the ``'\0'`` terminator. + + .. availability:: Linux >= 5.17 (kernel built with ``CONFIG_ANON_VMA_NAME`` option) + + .. versionadded:: next + .. method:: size() Return the length of the file, which can be larger than the size of the diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 753b1990eb3308..3c7e28a00c9c1a 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -592,6 +592,11 @@ mmap not be duplicated. (Contributed by Serhiy Storchaka in :gh:`78502`.) +* Added the :meth:`mmap.mmap.set_name` method + to annotate an anonymous memory mapping + if Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME ` (Linux 5.17 or newer). + (Contributed by Donghee Na in :gh:`142419`.) + os -- diff --git a/Include/internal/pycore_mmap.h b/Include/internal/pycore_mmap.h index 214fd4362a55fe..897816db01077f 100644 --- a/Include/internal/pycore_mmap.h +++ b/Include/internal/pycore_mmap.h @@ -17,25 +17,27 @@ extern "C" { #endif #if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__) -static inline void +static inline int _PyAnnotateMemoryMap(void *addr, size_t size, const char *name) { #ifndef Py_DEBUG if (!_Py_GetConfig()->dev_mode) { - return; + return 0; } #endif + // The name length cannot exceed 80 (including the '\0'). assert(strlen(name) < 80); - int old_errno = errno; - prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name); - /* Ignore errno from prctl */ - /* See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 */ - errno = old_errno; + int res = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name); + if (res < 0) { + return -1; + } + return 0; } #else -static inline void +static inline int _PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char *Py_UNUSED(name)) { + return 0; } #endif diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 368af0cf89c300..aad916ecfe2c27 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -6,6 +6,7 @@ from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok +import errno import unittest import os import re @@ -1165,6 +1166,46 @@ def test_flush_parameters(self): m.flush(PAGESIZE) m.flush(PAGESIZE, PAGESIZE) + @unittest.skipUnless(sys.platform == 'linux', 'Linux only') + @support.requires_linux_version(5, 17, 0) + def test_set_name(self): + # Test setting name on anonymous mmap + m = mmap.mmap(-1, PAGESIZE) + self.addCleanup(m.close) + try: + result = m.set_name('test_mapping') + except OSError as exc: + if exc.errno == errno.EINVAL: + # gh-142419: On Fedora, prctl(PR_SET_VMA_ANON_NAME) fails with + # EINVAL because the kernel option CONFIG_ANON_VMA_NAME is + # disabled. + # See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 + self.skipTest("prctl() failed with EINVAL") + else: + raise + self.assertIsNone(result) + + # Test name length limit (80 chars including prefix "cpython:mmap:" and '\0') + # Prefix is 13 chars, so max name is 66 chars + long_name = 'x' * 66 + result = m.set_name(long_name) + self.assertIsNone(result) + + # Test name too long + too_long_name = 'x' * 67 + with self.assertRaises(ValueError): + m.set_name(too_long_name) + + # Test that file-backed mmap raises error + with open(TESTFN, 'wb+') as f: + f.write(b'x' * PAGESIZE) + f.flush() + m2 = mmap.mmap(f.fileno(), PAGESIZE) + self.addCleanup(m2.close) + + with self.assertRaises(ValueError): + m2.set_name('should_fail') + class LargeMmapTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2025-12-10-02-31-43.gh-issue-142419.C8_LES.rst b/Misc/NEWS.d/next/Library/2025-12-10-02-31-43.gh-issue-142419.C8_LES.rst new file mode 100644 index 00000000000000..63955923cd157c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-10-02-31-43.gh-issue-142419.C8_LES.rst @@ -0,0 +1,3 @@ +:meth:`mmap.mmap.set_name` method added to annotate an anonymous memory map +if Linux kernel supports ``PR_SET_VMA_ANON_NAME`` (Linux 5.17 or newer). +Patch by Donghee Na. diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h index f7fc172b3af705..b63f7df2a7e334 100644 --- a/Modules/clinic/mmapmodule.c.h +++ b/Modules/clinic/mmapmodule.c.h @@ -479,6 +479,42 @@ mmap_mmap_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(mmap_mmap_set_name__doc__, +"set_name($self, name, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SET_NAME_METHODDEF \ + {"set_name", (PyCFunction)mmap_mmap_set_name, METH_O, mmap_mmap_set_name__doc__}, + +static PyObject * +mmap_mmap_set_name_impl(mmap_object *self, const char *name); + +static PyObject * +mmap_mmap_set_name(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + const char *name; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("set_name", "argument", "str", arg); + goto exit; + } + Py_ssize_t name_length; + name = PyUnicode_AsUTF8AndSize(arg, &name_length); + if (name == NULL) { + goto exit; + } + if (strlen(name) != (size_t)name_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + return_value = mmap_mmap_set_name_impl((mmap_object *)self, name); + +exit: + return return_value; +} + PyDoc_STRVAR(mmap_mmap_seekable__doc__, "seekable($self, /)\n" "--\n" @@ -796,4 +832,4 @@ mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #ifndef MMAP_MMAP_MADVISE_METHODDEF #define MMAP_MMAP_MADVISE_METHODDEF #endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ -/*[clinic end generated code: output=381f6cf4986ac867 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=fd9ca0ef425af934 input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 37003020de2688..ea20fb29c90228 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1117,6 +1117,47 @@ mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how) return NULL; } +/*[clinic input] +mmap.mmap.set_name + + name: str + / + +[clinic start generated code]*/ + +static PyObject * +mmap_mmap_set_name_impl(mmap_object *self, const char *name) +/*[clinic end generated code: output=1edaf4fd51277760 input=6c7dd91cad205f07]*/ +{ +#if defined(MAP_ANONYMOUS) && defined(__linux__) + const char *prefix = "cpython:mmap:"; + if (strlen(name) + strlen(prefix) > 79) { + PyErr_SetString(PyExc_ValueError, "name is too long"); + return NULL; + } + if (self->flags & MAP_ANONYMOUS) { + char buf[80]; + sprintf(buf, "%s%s", prefix, name); + if (_PyAnnotateMemoryMap(self->data, self->size, buf) < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + Py_RETURN_NONE; + } + else { + /* cannot name non-anonymous mappings */ + PyErr_SetString(PyExc_ValueError, + "Cannot set annotation on non-anonymous mappings"); + return NULL; + } +#else + /* naming not supported on this platform */ + PyErr_SetString(PyExc_NotImplementedError, + "Annotation of mmap is not supported on this platform"); + return NULL; +#endif +} + /*[clinic input] mmap.mmap.seekable @@ -1397,6 +1438,7 @@ static struct PyMethodDef mmap_object_methods[] = { MMAP_MMAP_RESIZE_METHODDEF MMAP_MMAP_SEEK_METHODDEF MMAP_MMAP_SEEKABLE_METHODDEF + MMAP_MMAP_SET_NAME_METHODDEF MMAP_MMAP_SIZE_METHODDEF MMAP_MMAP_TELL_METHODDEF MMAP_MMAP_WRITE_METHODDEF @@ -1952,7 +1994,11 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict) PyErr_SetFromErrno(PyExc_OSError); return NULL; } - _PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap"); +#ifdef MAP_ANONYMOUS + if (m_obj->flags & MAP_ANONYMOUS) { + (void)_PyAnnotateMemoryMap(m_obj->data, map_size, "cpython:mmap"); + } +#endif m_obj->access = (access_mode)access; return (PyObject *)m_obj; } diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index b1f9fa2e692265..c4ccc9e283feb3 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -468,7 +468,7 @@ _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size) if (ptr == MAP_FAILED) return NULL; assert(ptr != NULL); - _PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc"); + (void)_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc"); return ptr; #else return malloc(size); diff --git a/Python/jit.c b/Python/jit.c index ccafe0ce497f43..7660f6f9beac89 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -77,7 +77,7 @@ jit_alloc(size_t size) unsigned char *memory = mmap(NULL, size, prot, flags, -1, 0); int failed = memory == MAP_FAILED; if (!failed) { - _PyAnnotateMemoryMap(memory, size, "cpython:jit"); + (void)_PyAnnotateMemoryMap(memory, size, "cpython:jit"); } #endif if (failed) { diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c index af7d8f9f1ec0ae..0ffa906d85cc6b 100644 --- a/Python/perf_jit_trampoline.c +++ b/Python/perf_jit_trampoline.c @@ -1086,7 +1086,8 @@ static void* perf_map_jit_init(void) { close(fd); return NULL; // Memory mapping failed } - _PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size, "cpython:perf_jit_trampoline"); + (void)_PyAnnotateMemoryMap(perf_jit_map_state.mapped_buffer, page_size, + "cpython:perf_jit_trampoline"); #endif perf_jit_map_state.mapped_size = page_size; diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c index 669a47ae17377a..335d8ac7dadd10 100644 --- a/Python/perf_trampoline.c +++ b/Python/perf_trampoline.c @@ -291,7 +291,7 @@ new_code_arena(void) perf_status = PERF_STATUS_FAILED; return -1; } - _PyAnnotateMemoryMap(memory, mem_size, "cpython:perf_trampoline"); + (void)_PyAnnotateMemoryMap(memory, mem_size, "cpython:perf_trampoline"); void *start = &_Py_trampoline_func_start; void *end = &_Py_trampoline_func_end; size_t code_size = end - start; From e4058d7cb115286c3c53e0a0be2a7b60af46e073 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 18 Dec 2025 16:43:44 +0000 Subject: [PATCH 010/105] GH-142513: Reimplement executor management (GH-142931) * Invalidating an executor does not cause arbitrary code to run * Executors are only freed at safe points --- Include/internal/pycore_interp_structs.h | 1 - Include/internal/pycore_optimizer.h | 7 - Python/ceval_gil.c | 6 + Python/optimizer.c | 181 +++++++++++------------ Python/pystate.c | 1 - 5 files changed, 90 insertions(+), 106 deletions(-) diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index 6b3d5711b92971..818c4f159591fe 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -947,7 +947,6 @@ struct _is { struct _PyExecutorObject *executor_deletion_list_head; struct _PyExecutorObject *cold_executor; struct _PyExecutorObject *cold_dynamic_executor; - int executor_deletion_list_remaining_capacity; size_t executor_creation_counter; _rare_events rare_events; PyDict_WatchCallback builtins_dict_watcher; diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 295d4909e14735..3ee62f1728321d 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -25,7 +25,6 @@ typedef struct { uint8_t opcode; uint8_t oparg; uint8_t valid; - uint8_t linked; uint8_t chain_depth; // Must be big enough for MAX_CHAIN_DEPTH - 1. bool warm; int32_t index; // Index of ENTER_EXECUTOR (if code isn't NULL, below). @@ -55,11 +54,6 @@ typedef struct _PyExecutorObject { _PyExitData exits[1]; } _PyExecutorObject; -/* If pending deletion list gets large enough, then scan, - * and free any executors that aren't executing - * i.e. any that aren't a thread's current_executor. */ -#define EXECUTOR_DELETE_LIST_MAX 100 - // Export for '_opcode' shared extension (JIT compiler). PyAPI_FUNC(_PyExecutorObject*) _Py_GetExecutor(PyCodeObject *code, int offset); @@ -80,7 +74,6 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp); #else # define _Py_Executors_InvalidateDependency(A, B, C) ((void)0) # define _Py_Executors_InvalidateAll(A, B) ((void)0) -# define _Py_Executors_InvalidateCold(A) ((void)0) #endif diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index f6ada3892f801d..88cc66e97f3424 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -1397,13 +1397,19 @@ _Py_HandlePending(PyThreadState *tstate) if ((breaker & _PY_GC_SCHEDULED_BIT) != 0) { _Py_unset_eval_breaker_bit(tstate, _PY_GC_SCHEDULED_BIT); _Py_RunGC(tstate); +#ifdef _Py_TIER2 + _Py_ClearExecutorDeletionList(tstate->interp); +#endif } +#ifdef _Py_TIER2 if ((breaker & _PY_EVAL_JIT_INVALIDATE_COLD_BIT) != 0) { _Py_unset_eval_breaker_bit(tstate, _PY_EVAL_JIT_INVALIDATE_COLD_BIT); _Py_Executors_InvalidateCold(tstate->interp); tstate->interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD; + _Py_ClearExecutorDeletionList(tstate->interp); } +#endif /* GIL drop request */ if ((breaker & _PY_GIL_DROP_REQUEST_BIT) != 0) { diff --git a/Python/optimizer.c b/Python/optimizer.c index fc984a5374a554..1e905850e3de6b 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -246,8 +246,6 @@ get_oparg(PyObject *self, PyObject *Py_UNUSED(ignored)) ///////////////////// Experimental UOp Optimizer ///////////////////// static int executor_clear(PyObject *executor); -static void unlink_executor(_PyExecutorObject *executor); - void _PyExecutor_Free(_PyExecutorObject *self) @@ -258,63 +256,76 @@ _PyExecutor_Free(_PyExecutorObject *self) PyObject_GC_Del(self); } +static void executor_invalidate(PyObject *op); + +static void +executor_clear_exits(_PyExecutorObject *executor) +{ + _PyExecutorObject *cold = _PyExecutor_GetColdExecutor(); + _PyExecutorObject *cold_dynamic = _PyExecutor_GetColdDynamicExecutor(); + for (uint32_t i = 0; i < executor->exit_count; i++) { + _PyExitData *exit = &executor->exits[i]; + exit->temperature = initial_unreachable_backoff_counter(); + _PyExecutorObject *old = executor->exits[i].executor; + exit->executor = exit->is_dynamic ? cold_dynamic : cold; + Py_DECREF(old); + } +} + + void _Py_ClearExecutorDeletionList(PyInterpreterState *interp) { + if (interp->executor_deletion_list_head == NULL) { + return; + } _PyRuntimeState *runtime = &_PyRuntime; HEAD_LOCK(runtime); PyThreadState* ts = PyInterpreterState_ThreadHead(interp); + while (ts) { + _PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor; + Py_XINCREF(current); + ts = ts->next; + } HEAD_UNLOCK(runtime); + _PyExecutorObject *keep_list = NULL; + do { + _PyExecutorObject *exec = interp->executor_deletion_list_head; + interp->executor_deletion_list_head = exec->vm_data.links.next; + if (Py_REFCNT(exec) == 0) { + _PyExecutor_Free(exec); + } else { + exec->vm_data.links.next = keep_list; + keep_list = exec; + } + } while (interp->executor_deletion_list_head != NULL); + interp->executor_deletion_list_head = keep_list; + HEAD_LOCK(runtime); + ts = PyInterpreterState_ThreadHead(interp); while (ts) { _PyExecutorObject *current = (_PyExecutorObject *)ts->current_executor; if (current != NULL) { - /* Anything in this list will be unlinked, so we can reuse the - * linked field as a reachability marker. */ - current->vm_data.linked = 1; + _Py_DECREF_NO_DEALLOC((PyObject *)current); } - HEAD_LOCK(runtime); - ts = PyThreadState_Next(ts); - HEAD_UNLOCK(runtime); - } - _PyExecutorObject **prev_to_next_ptr = &interp->executor_deletion_list_head; - _PyExecutorObject *exec = *prev_to_next_ptr; - while (exec != NULL) { - if (exec->vm_data.linked) { - // This executor is currently executing - exec->vm_data.linked = 0; - prev_to_next_ptr = &exec->vm_data.links.next; - } - else { - *prev_to_next_ptr = exec->vm_data.links.next; - _PyExecutor_Free(exec); - } - exec = *prev_to_next_ptr; + ts = ts->next; } - interp->executor_deletion_list_remaining_capacity = EXECUTOR_DELETE_LIST_MAX; + HEAD_UNLOCK(runtime); } static void add_to_pending_deletion_list(_PyExecutorObject *self) { PyInterpreterState *interp = PyInterpreterState_Get(); + self->vm_data.links.previous = NULL; self->vm_data.links.next = interp->executor_deletion_list_head; interp->executor_deletion_list_head = self; - if (interp->executor_deletion_list_remaining_capacity > 0) { - interp->executor_deletion_list_remaining_capacity--; - } - else { - _Py_ClearExecutorDeletionList(interp); - } } static void uop_dealloc(PyObject *op) { _PyExecutorObject *self = _PyExecutorObject_CAST(op); - _PyObject_GC_UNTRACK(self); + executor_invalidate(op); assert(self->vm_data.code == NULL); - unlink_executor(self); - // Once unlinked it becomes impossible to invalidate an executor, so do it here. - self->vm_data.valid = 0; add_to_pending_deletion_list(self); } @@ -1621,7 +1632,6 @@ link_executor(_PyExecutorObject *executor) head->vm_data.links.previous = executor; interp->executor_list_head = executor; } - executor->vm_data.linked = true; /* executor_list_head must be first in list */ assert(interp->executor_list_head->vm_data.links.previous == NULL); } @@ -1629,11 +1639,7 @@ link_executor(_PyExecutorObject *executor) static void unlink_executor(_PyExecutorObject *executor) { - if (!executor->vm_data.linked) { - return; - } _PyExecutorLinkListNode *links = &executor->vm_data.links; - assert(executor->vm_data.valid); _PyExecutorObject *next = links->next; _PyExecutorObject *prev = links->previous; if (next != NULL) { @@ -1648,7 +1654,6 @@ unlink_executor(_PyExecutorObject *executor) assert(interp->executor_list_head == executor); interp->executor_list_head = next; } - executor->vm_data.linked = false; } /* This must be called by optimizers before using the executor */ @@ -1662,61 +1667,47 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s link_executor(executor); } -_PyExecutorObject * -_PyExecutor_GetColdExecutor(void) +static _PyExecutorObject * +make_cold_executor(uint16_t opcode) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->cold_executor != NULL) { - return interp->cold_executor; - } _PyExecutorObject *cold = allocate_executor(0, 1); if (cold == NULL) { Py_FatalError("Cannot allocate core JIT code"); } - ((_PyUOpInstruction *)cold->trace)->opcode = _COLD_EXIT_r00; -#ifdef _Py_JIT - cold->jit_code = NULL; - cold->jit_size = 0; + ((_PyUOpInstruction *)cold->trace)->opcode = opcode; // This is initialized to true so we can prevent the executor // from being immediately detected as cold and invalidated. cold->vm_data.warm = true; +#ifdef _Py_JIT + cold->jit_code = NULL; + cold->jit_size = 0; if (_PyJIT_Compile(cold, cold->trace, 1)) { Py_DECREF(cold); Py_FatalError("Cannot allocate core JIT code"); } #endif _Py_SetImmortal((PyObject *)cold); - interp->cold_executor = cold; return cold; } _PyExecutorObject * -_PyExecutor_GetColdDynamicExecutor(void) +_PyExecutor_GetColdExecutor(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->cold_dynamic_executor != NULL) { - assert(interp->cold_dynamic_executor->trace[0].opcode == _COLD_DYNAMIC_EXIT_r00); - return interp->cold_dynamic_executor; - } - _PyExecutorObject *cold = allocate_executor(0, 1); - if (cold == NULL) { - Py_FatalError("Cannot allocate core JIT code"); + if (interp->cold_executor == NULL) { + return interp->cold_executor = make_cold_executor(_COLD_EXIT_r00);; } - ((_PyUOpInstruction *)cold->trace)->opcode = _COLD_DYNAMIC_EXIT_r00; -#ifdef _Py_JIT - cold->jit_code = NULL; - cold->jit_size = 0; - // This is initialized to true so we can prevent the executor - // from being immediately detected as cold and invalidated. - cold->vm_data.warm = true; - if (_PyJIT_Compile(cold, cold->trace, 1)) { - Py_DECREF(cold); - Py_FatalError("Cannot allocate core JIT code"); + return interp->cold_executor; +} + +_PyExecutorObject * +_PyExecutor_GetColdDynamicExecutor(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + if (interp->cold_dynamic_executor == NULL) { + interp->cold_dynamic_executor = make_cold_executor(_COLD_DYNAMIC_EXIT_r00); } -#endif - _Py_SetImmortal((PyObject *)cold); - interp->cold_dynamic_executor = cold; - return cold; + return interp->cold_dynamic_executor; } void @@ -1755,32 +1746,28 @@ _Py_ExecutorDetach(_PyExecutorObject *executor) Py_DECREF(executor); } -static int -executor_clear(PyObject *op) +/* Executors can be invalidated at any time, + even with a stop-the-world lock held. + Consequently it must not run arbitrary code, + including Py_DECREF with a non-executor. */ +static void +executor_invalidate(PyObject *op) { _PyExecutorObject *executor = _PyExecutorObject_CAST(op); if (!executor->vm_data.valid) { - return 0; + return; } - assert(executor->vm_data.valid == 1); - unlink_executor(executor); executor->vm_data.valid = 0; - - /* It is possible for an executor to form a reference - * cycle with itself, so decref'ing a side exit could - * free the executor unless we hold a strong reference to it - */ - _PyExecutorObject *cold = _PyExecutor_GetColdExecutor(); - Py_INCREF(executor); - for (uint32_t i = 0; i < executor->exit_count; i++) { - executor->exits[i].temperature = initial_unreachable_backoff_counter(); - _PyExecutorObject *e = executor->exits[i].executor; - executor->exits[i].executor = cold; - Py_DECREF(e); - } + unlink_executor(executor); + executor_clear_exits(executor); _Py_ExecutorDetach(executor); - Py_DECREF(executor); - return 0; + _PyObject_GC_UNTRACK(op); +} + +static int +executor_clear(PyObject *op) +{ + executor_invalidate(op); } void @@ -1805,7 +1792,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is if (invalidate == NULL) { goto error; } - /* Clearing an executor can deallocate others, so we need to make a list of + /* Clearing an executor can clear others, so we need to make a list of * executors to invalidate first */ for (_PyExecutorObject *exec = interp->executor_list_head; exec != NULL;) { assert(exec->vm_data.valid); @@ -1819,7 +1806,7 @@ _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is } for (Py_ssize_t i = 0; i < PyList_GET_SIZE(invalidate); i++) { PyObject *exec = PyList_GET_ITEM(invalidate, i); - executor_clear(exec); + executor_invalidate(exec); if (is_invalidation) { OPT_STAT_INC(executors_invalidated); } @@ -1851,13 +1838,13 @@ _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation) { while (interp->executor_list_head) { _PyExecutorObject *executor = interp->executor_list_head; - assert(executor->vm_data.valid == 1 && executor->vm_data.linked == 1); + assert(executor->vm_data.valid); if (executor->vm_data.code) { // Clear the entire code object so its co_executors array be freed: _PyCode_Clear_Executors(executor->vm_data.code); } else { - executor_clear((PyObject *)executor); + executor_invalidate((PyObject *)executor); } if (is_invalidation) { OPT_STAT_INC(executors_invalidated); @@ -1892,7 +1879,7 @@ _Py_Executors_InvalidateCold(PyInterpreterState *interp) } for (Py_ssize_t i = 0; i < PyList_GET_SIZE(invalidate); i++) { PyObject *exec = PyList_GET_ITEM(invalidate, i); - executor_clear(exec); + executor_invalidate(exec); } Py_DECREF(invalidate); return; diff --git a/Python/pystate.c b/Python/pystate.c index 4bf89a234266e4..7ea8ef91f107a9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -570,7 +570,6 @@ init_interpreter(PyInterpreterState *interp, interp->compiling = false; interp->executor_list_head = NULL; interp->executor_deletion_list_head = NULL; - interp->executor_deletion_list_remaining_capacity = 0; interp->executor_creation_counter = JIT_CLEANUP_THRESHOLD; if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ From 4a8ecbad809dedd9268973d533f24117dfc2e5ba Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 18 Dec 2025 19:04:28 +0200 Subject: [PATCH 011/105] gh-142681: Move NormalizationTest-3.2.0.txt to more safe place. (GH-142935) --- Lib/test/{data => }/NormalizationTest-3.2.0.txt | 0 Lib/test/test_unicodedata.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Lib/test/{data => }/NormalizationTest-3.2.0.txt (100%) diff --git a/Lib/test/data/NormalizationTest-3.2.0.txt b/Lib/test/NormalizationTest-3.2.0.txt similarity index 100% rename from Lib/test/data/NormalizationTest-3.2.0.txt rename to Lib/test/NormalizationTest-3.2.0.txt diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index f5ab25c602a69d..b1888b6db9be6a 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -759,7 +759,7 @@ def test_normalization(self): @requires_resource('cpu') def test_normalization_3_2_0(self): - testdatafile = findfile('NormalizationTest-3.2.0.txt', 'data') + testdatafile = findfile('NormalizationTest-3.2.0.txt') with open(testdatafile, encoding='utf-8') as testdata: self.run_normalization_tests(testdata, unicodedata.ucd_3_2_0) From e22c49522bd119d2d2690989ea269e2f5a3009db Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Thu, 18 Dec 2025 22:48:56 +0530 Subject: [PATCH 012/105] gh-142890: remove unnecessary interp parameter from dict functions and `_PyDict_NotifyEvent` (#142923) --- Include/internal/pycore_dict.h | 3 +- Objects/dictobject.c | 105 +++++++++++++-------------------- Python/bytecodes.c | 2 +- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 5 files changed, 46 insertions(+), 68 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index 1193f496da132d..a7005a3b8e2fab 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -272,8 +272,7 @@ _PyDict_SendEvent(int watcher_bits, PyObject *value); static inline void -_PyDict_NotifyEvent(PyInterpreterState *interp, - PyDict_WatchEvent event, +_PyDict_NotifyEvent(PyDict_WatchEvent event, PyDictObject *mp, PyObject *key, PyObject *value) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 49a42a35acb8fd..5a2bb7d3d8cd2d 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1771,7 +1771,7 @@ insertion_resize(PyDictObject *mp, int unicode) } static inline int -insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp, +insert_combined_dict(PyDictObject *mp, Py_hash_t hash, PyObject *key, PyObject *value) { // gh-140551: If dict was cleared in _Py_dict_lookup, @@ -1789,7 +1789,7 @@ insert_combined_dict(PyInterpreterState *interp, PyDictObject *mp, } } - _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value); + _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); FT_ATOMIC_STORE_UINT32_RELAXED(mp->ma_keys->dk_version, 0); Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); @@ -1846,19 +1846,19 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) } static void -insert_split_value(PyInterpreterState *interp, PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix) +insert_split_value(PyDictObject *mp, PyObject *key, PyObject *value, Py_ssize_t ix) { assert(PyUnicode_CheckExact(key)); ASSERT_DICT_LOCKED(mp); PyObject *old_value = mp->ma_values->values[ix]; if (old_value == NULL) { - _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value); + _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value)); _PyDictValues_AddToInsertionOrder(mp->ma_values, ix); STORE_USED(mp, mp->ma_used + 1); } else { - _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value); + _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value); STORE_SPLIT_VALUE(mp, ix, Py_NewRef(value)); // old_value should be DECREFed after GC track checking is done, if not, it could raise a segmentation fault, // when dict only holds the strong reference to value in ep->me_value. @@ -1874,7 +1874,7 @@ Returns -1 if an error occurred, or 0 on success. Consumes key and value references. */ static int -insertdict(PyInterpreterState *interp, PyDictObject *mp, +insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { PyObject *old_value; @@ -1885,7 +1885,7 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, if (_PyDict_HasSplitTable(mp) && PyUnicode_CheckExact(key)) { ix = insert_split_key(mp->ma_keys, key, hash); if (ix != DKIX_EMPTY) { - insert_split_value(interp, mp, key, value, ix); + insert_split_value(mp, key, value, ix); Py_DECREF(key); Py_DECREF(value); return 0; @@ -1903,7 +1903,7 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, // into DICT_KEYS_GENERAL table if key is not Unicode. // We don't convert it before _Py_dict_lookup because non-Unicode key // may change generic table into Unicode table. - if (insert_combined_dict(interp, mp, hash, key, value) < 0) { + if (insert_combined_dict(mp, hash, key, value) < 0) { goto Fail; } STORE_USED(mp, mp->ma_used + 1); @@ -1912,7 +1912,7 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, } if (old_value != value) { - _PyDict_NotifyEvent(interp, PyDict_EVENT_MODIFIED, mp, key, value); + _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, mp, key, value); assert(old_value != NULL); if (DK_IS_UNICODE(mp->ma_keys)) { if (_PyDict_HasSplitTable(mp)) { @@ -1942,7 +1942,7 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp, // Same as insertdict but specialized for ma_keys == Py_EMPTY_KEYS. // Consumes key and value references. static int -insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, +insert_to_emptydict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { assert(mp->ma_keys == Py_EMPTY_KEYS); @@ -1955,7 +1955,7 @@ insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp, Py_DECREF(value); return -1; } - _PyDict_NotifyEvent(interp, PyDict_EVENT_ADDED, mp, key, value); + _PyDict_NotifyEvent(PyDict_EVENT_ADDED, mp, key, value); /* We don't decref Py_EMPTY_KEYS here because it is immortal. */ assert(mp->ma_values == NULL); @@ -2658,13 +2658,11 @@ setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value) return -1; } - PyInterpreterState *interp = _PyInterpreterState_GET(); - if (mp->ma_keys == Py_EMPTY_KEYS) { - return insert_to_emptydict(interp, mp, key, hash, value); + return insert_to_emptydict(mp, key, hash, value); } /* insertdict() handles any resizing that might be necessary */ - return insertdict(interp, mp, key, hash, value); + return insertdict(mp, key, hash, value); } int @@ -2710,12 +2708,11 @@ int _PyDict_SetItem_KnownHash_LockHeld(PyDictObject *mp, PyObject *key, PyObject *value, Py_hash_t hash) { - PyInterpreterState *interp = _PyInterpreterState_GET(); if (mp->ma_keys == Py_EMPTY_KEYS) { - return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value)); + return insert_to_emptydict(mp, Py_NewRef(key), hash, Py_NewRef(value)); } /* insertdict() handles any resizing that might be necessary */ - return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value)); + return insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); } int @@ -2836,8 +2833,7 @@ _PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash) return -1; } - PyInterpreterState *interp = _PyInterpreterState_GET(); - _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); delitem_common(mp, hash, ix, old_value); return 0; } @@ -2883,8 +2879,7 @@ delitemif_lock_held(PyObject *op, PyObject *key, return -1; if (res > 0) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); delitem_common(mp, hash, ix, old_value); return 1; } else { @@ -2928,8 +2923,7 @@ clear_lock_held(PyObject *op) return; } /* Empty the dict... */ - PyInterpreterState *interp = _PyInterpreterState_GET(); - _PyDict_NotifyEvent(interp, PyDict_EVENT_CLEARED, mp, NULL, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_CLEARED, mp, NULL, NULL); // We don't inc ref empty keys because they're immortal ensure_shared_on_resize(mp); STORE_USED(mp, 0); @@ -3095,8 +3089,7 @@ _PyDict_Pop_KnownHash(PyDictObject *mp, PyObject *key, Py_hash_t hash, } assert(old_value != NULL); - PyInterpreterState *interp = _PyInterpreterState_GET(); - _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, mp, key, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DELETED, mp, key, NULL); delitem_common(mp, hash, ix, Py_NewRef(old_value)); ASSERT_CONSISTENT(mp); @@ -3191,8 +3184,7 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) } static PyDictObject * -dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, - PyObject *iterable, PyObject *value) +dict_dict_fromkeys(PyDictObject *mp, PyObject *iterable, PyObject *value) { PyObject *oldvalue; Py_ssize_t pos = 0; @@ -3208,8 +3200,7 @@ dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, } while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) { - if (insertdict(interp, mp, - Py_NewRef(key), hash, Py_NewRef(value))) { + if (insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value))) { Py_DECREF(mp); return NULL; } @@ -3218,8 +3209,7 @@ dict_dict_fromkeys(PyInterpreterState *interp, PyDictObject *mp, } static PyDictObject * -dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp, - PyObject *iterable, PyObject *value) +dict_set_fromkeys(PyDictObject *mp, PyObject *iterable, PyObject *value) { Py_ssize_t pos = 0; PyObject *key; @@ -3234,7 +3224,7 @@ dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp, _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(iterable); while (_PySet_NextEntryRef(iterable, &pos, &key, &hash)) { - if (insertdict(interp, mp, key, hash, Py_NewRef(value))) { + if (insertdict(mp, key, hash, Py_NewRef(value))) { Py_DECREF(mp); return NULL; } @@ -3250,7 +3240,6 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *key; PyObject *d; int status; - PyInterpreterState *interp = _PyInterpreterState_GET(); d = _PyObject_CallNoArgs(cls); if (d == NULL) @@ -3262,7 +3251,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyDictObject *mp = (PyDictObject *)d; Py_BEGIN_CRITICAL_SECTION2(d, iterable); - d = (PyObject *)dict_dict_fromkeys(interp, mp, iterable, value); + d = (PyObject *)dict_dict_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION2(); return d; } @@ -3270,7 +3259,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyDictObject *mp = (PyDictObject *)d; Py_BEGIN_CRITICAL_SECTION2(d, iterable); - d = (PyObject *)dict_set_fromkeys(interp, mp, iterable, value); + d = (PyObject *)dict_set_fromkeys(mp, iterable, value); Py_END_CRITICAL_SECTION2(); return d; } @@ -3320,9 +3309,8 @@ static void dict_dealloc(PyObject *self) { PyDictObject *mp = (PyDictObject *)self; - PyInterpreterState *interp = _PyInterpreterState_GET(); _PyObject_ResurrectStart(self); - _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DEALLOCATED, mp, NULL, NULL); if (_PyObject_ResurrectEnd(self)) { return; } @@ -3844,7 +3832,7 @@ PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override) } static int -dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *other, int override) +dict_dict_merge(PyDictObject *mp, PyDictObject *other, int override) { ASSERT_DICT_LOCKED(mp); ASSERT_DICT_LOCKED(other); @@ -3867,7 +3855,7 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *othe (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE || USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used) ) { - _PyDict_NotifyEvent(interp, PyDict_EVENT_CLONED, mp, (PyObject *)other, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_CLONED, mp, (PyObject *)other, NULL); PyDictKeysObject *keys = clone_combined_dict_keys(other); if (keys == NULL) return -1; @@ -3908,14 +3896,12 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *othe Py_INCREF(key); Py_INCREF(value); if (override == 1) { - err = insertdict(interp, mp, - Py_NewRef(key), hash, Py_NewRef(value)); + err = insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); } else { err = _PyDict_Contains_KnownHash((PyObject *)mp, key, hash); if (err == 0) { - err = insertdict(interp, mp, - Py_NewRef(key), hash, Py_NewRef(value)); + err = insertdict(mp, Py_NewRef(key), hash, Py_NewRef(value)); } else if (err > 0) { if (override != 0) { @@ -3942,7 +3928,7 @@ dict_dict_merge(PyInterpreterState *interp, PyDictObject *mp, PyDictObject *othe } static int -dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override) +dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; @@ -3963,7 +3949,7 @@ dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override) other = (PyDictObject*)b; int res; Py_BEGIN_CRITICAL_SECTION2(a, b); - res = dict_dict_merge(interp, (PyDictObject *)a, other, override); + res = dict_dict_merge((PyDictObject *)a, other, override); ASSERT_CONSISTENT(a); Py_END_CRITICAL_SECTION2(); return res; @@ -4044,23 +4030,20 @@ dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override) int PyDict_Update(PyObject *a, PyObject *b) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return dict_merge(interp, a, b, 1); + return dict_merge(a, b, 1); } int PyDict_Merge(PyObject *a, PyObject *b, int override) { - PyInterpreterState *interp = _PyInterpreterState_GET(); /* XXX Deprecate override not in (0, 1). */ - return dict_merge(interp, a, b, override != 0); + return dict_merge(a, b, override != 0); } int _PyDict_MergeEx(PyObject *a, PyObject *b, int override) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return dict_merge(interp, a, b, override); + return dict_merge(a, b, override); } /*[clinic input] @@ -4102,7 +4085,6 @@ copy_lock_held(PyObject *o) { PyObject *copy; PyDictObject *mp; - PyInterpreterState *interp = _PyInterpreterState_GET(); ASSERT_DICT_LOCKED(o); @@ -4172,7 +4154,7 @@ copy_lock_held(PyObject *o) copy = PyDict_New(); if (copy == NULL) return NULL; - if (dict_merge(interp, copy, o, 1) == 0) + if (dict_merge(copy, o, 1) == 0) return copy; Py_DECREF(copy); return NULL; @@ -4367,7 +4349,6 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu PyObject *value; Py_hash_t hash; Py_ssize_t ix; - PyInterpreterState *interp = _PyInterpreterState_GET(); ASSERT_DICT_LOCKED(d); @@ -4389,7 +4370,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu } if (mp->ma_keys == Py_EMPTY_KEYS) { - if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash, + if (insert_to_emptydict(mp, Py_NewRef(key), hash, Py_NewRef(default_value)) < 0) { if (result) { *result = NULL; @@ -4408,7 +4389,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu PyObject *value = mp->ma_values->values[ix]; int already_present = value != NULL; if (!already_present) { - insert_split_value(interp, mp, key, default_value, ix); + insert_split_value(mp, key, default_value, ix); value = default_value; } if (result) { @@ -4432,7 +4413,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu value = default_value; // See comment to this function in insertdict. - if (insert_combined_dict(interp, mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) { + if (insert_combined_dict(mp, hash, Py_NewRef(key), Py_NewRef(value)) < 0) { Py_DECREF(key); Py_DECREF(value); if (result) { @@ -4554,7 +4535,6 @@ dict_popitem_impl(PyDictObject *self) { Py_ssize_t i, j; PyObject *res; - PyInterpreterState *interp = _PyInterpreterState_GET(); ASSERT_DICT_LOCKED(self); @@ -4596,7 +4576,7 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; - _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, self, key, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); hash = unicode_get_hash(key); value = ep0[i].me_value; STORE_KEY(&ep0[i], NULL); @@ -4611,7 +4591,7 @@ dict_popitem_impl(PyDictObject *self) assert(i >= 0); key = ep0[i].me_key; - _PyDict_NotifyEvent(interp, PyDict_EVENT_DELETED, self, key, NULL); + _PyDict_NotifyEvent(PyDict_EVENT_DELETED, self, key, NULL); hash = ep0[i].me_hash; value = ep0[i].me_value; STORE_KEY(&ep0[i], NULL); @@ -6925,11 +6905,10 @@ store_instance_attr_lock_held(PyObject *obj, PyDictValues *values, } if (dict) { - PyInterpreterState *interp = _PyInterpreterState_GET(); PyDict_WatchEvent event = (old_value == NULL ? PyDict_EVENT_ADDED : value == NULL ? PyDict_EVENT_DELETED : PyDict_EVENT_MODIFIED); - _PyDict_NotifyEvent(interp, event, dict, name, value); + _PyDict_NotifyEvent(event, dict, name, value); } FT_ATOMIC_STORE_PTR_RELEASE(values->values[ix], Py_XNewRef(value)); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 07944f624ede95..3e3b3d2f446d33 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2628,7 +2628,7 @@ dummy_func( UNLOCK_OBJECT(dict); DEOPT_IF(true); } - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); + _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(dict); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9f3a207929ff9f..b7ee752cd44e16 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -8825,7 +8825,7 @@ stack_pointer += 2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); + _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(dict); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8d3119e9169d19..28dc7b25f0d2cc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -10822,7 +10822,7 @@ } } _PyFrame_SetStackPointer(frame, stack_pointer); - _PyDict_NotifyEvent(tstate->interp, PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); + _PyDict_NotifyEvent(PyDict_EVENT_MODIFIED, dict, name, PyStackRef_AsPyObjectBorrow(value)); stack_pointer = _PyFrame_GetStackPointer(frame); FT_ATOMIC_STORE_PTR_RELEASE(ep->me_value, PyStackRef_AsPyObjectSteal(value)); UNLOCK_OBJECT(dict); From f54d44d3331ef0bc19f1437f32ffde2e49c07c22 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 18 Dec 2025 13:11:51 -0500 Subject: [PATCH 013/105] gh-129068: Make range iterators thread-safe (gh-142886) Now that we specialize range iteration in the interpreter for the common case where the iterator has only one reference, there's not a significant performance cost to making the iteration thread-safe. --- ...-12-17-10-49-03.gh-issue-129068.GlYnrO.rst | 2 + Objects/clinic/rangeobject.c.h | 150 ++++++++++++++++++ Objects/rangeobject.c | 131 +++++++++++---- Tools/tsan/suppressions_free_threading.txt | 6 - 4 files changed, 251 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst create mode 100644 Objects/clinic/rangeobject.c.h diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst new file mode 100644 index 00000000000000..16b19524cd4057 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-17-10-49-03.gh-issue-129068.GlYnrO.rst @@ -0,0 +1,2 @@ +Make concurrent iteration over the same range iterator thread-safe in the +free threading build. diff --git a/Objects/clinic/rangeobject.c.h b/Objects/clinic/rangeobject.c.h new file mode 100644 index 00000000000000..d9142eddde4b17 --- /dev/null +++ b/Objects/clinic/rangeobject.c.h @@ -0,0 +1,150 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() + +PyDoc_STRVAR(range_iterator___length_hint____doc__, +"__length_hint__($self, /)\n" +"--\n" +"\n" +"Private method returning an estimate of len(list(it))."); + +#define RANGE_ITERATOR___LENGTH_HINT___METHODDEF \ + {"__length_hint__", (PyCFunction)range_iterator___length_hint__, METH_NOARGS, range_iterator___length_hint____doc__}, + +static PyObject * +range_iterator___length_hint___impl(_PyRangeIterObject *r); + +static PyObject * +range_iterator___length_hint__(PyObject *r, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___length_hint___impl((_PyRangeIterObject *)r); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(range_iterator___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Return state information for pickling."); + +#define RANGE_ITERATOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)range_iterator___reduce__, METH_NOARGS, range_iterator___reduce____doc__}, + +static PyObject * +range_iterator___reduce___impl(_PyRangeIterObject *r); + +static PyObject * +range_iterator___reduce__(PyObject *r, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___reduce___impl((_PyRangeIterObject *)r); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(range_iterator___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n" +"Set state information for unpickling."); + +#define RANGE_ITERATOR___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)range_iterator___setstate__, METH_O, range_iterator___setstate____doc__}, + +static PyObject * +range_iterator___setstate___impl(_PyRangeIterObject *r, PyObject *state); + +static PyObject * +range_iterator___setstate__(PyObject *r, PyObject *state) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = range_iterator___setstate___impl((_PyRangeIterObject *)r, state); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(longrange_iterator___length_hint____doc__, +"__length_hint__($self, /)\n" +"--\n" +"\n" +"Private method returning an estimate of len(list(it))."); + +#define LONGRANGE_ITERATOR___LENGTH_HINT___METHODDEF \ + {"__length_hint__", (PyCFunction)longrange_iterator___length_hint__, METH_NOARGS, longrange_iterator___length_hint____doc__}, + +static PyObject * +longrange_iterator___length_hint___impl(longrangeiterobject *r); + +static PyObject * +longrange_iterator___length_hint__(PyObject *r, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___length_hint___impl((longrangeiterobject *)r); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(longrange_iterator___reduce____doc__, +"__reduce__($self, /)\n" +"--\n" +"\n" +"Return state information for pickling."); + +#define LONGRANGE_ITERATOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)longrange_iterator___reduce__, METH_NOARGS, longrange_iterator___reduce____doc__}, + +static PyObject * +longrange_iterator___reduce___impl(longrangeiterobject *r); + +static PyObject * +longrange_iterator___reduce__(PyObject *r, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___reduce___impl((longrangeiterobject *)r); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(longrange_iterator___setstate____doc__, +"__setstate__($self, state, /)\n" +"--\n" +"\n" +"Set state information for unpickling."); + +#define LONGRANGE_ITERATOR___SETSTATE___METHODDEF \ + {"__setstate__", (PyCFunction)longrange_iterator___setstate__, METH_O, longrange_iterator___setstate____doc__}, + +static PyObject * +longrange_iterator___setstate___impl(longrangeiterobject *r, PyObject *state); + +static PyObject * +longrange_iterator___setstate__(PyObject *r, PyObject *state) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(r); + return_value = longrange_iterator___setstate___impl((longrangeiterobject *)r, state); + Py_END_CRITICAL_SECTION(); + + return return_value; +} +/*[clinic end generated code: output=719c0e4c81fe0f4a input=a9049054013a1b77]*/ diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index e93346fb27703f..55b7f108730728 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -9,6 +9,21 @@ #include "pycore_range.h" #include "pycore_tuple.h" // _PyTuple_ITEMS() +typedef struct { + PyObject_HEAD + PyObject *start; + PyObject *step; + PyObject *len; +} longrangeiterobject; + +/*[clinic input] +class range_iterator "_PyRangeIterObject *" "&PyRangeIter_Type" +class longrange_iterator "longrangeiterobject *" "&PyLongRangeIter_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c7d97a63d1cfa6b3]*/ + +#include "clinic/rangeobject.c.h" + /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -830,30 +845,46 @@ PyTypeObject PyRange_Type = { static PyObject * rangeiter_next(PyObject *op) { + PyObject *ret = NULL; + Py_BEGIN_CRITICAL_SECTION(op); _PyRangeIterObject *r = (_PyRangeIterObject*)op; if (r->len > 0) { long result = r->start; r->start = result + r->step; r->len--; - return PyLong_FromLong(result); + ret = PyLong_FromLong(result); } - return NULL; + Py_END_CRITICAL_SECTION(); + return ret; } +/*[clinic input] +@critical_section +range_iterator.__length_hint__ + self as r: self(type="_PyRangeIterObject *") + +Private method returning an estimate of len(list(it)). +[clinic start generated code]*/ + static PyObject * -rangeiter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) +range_iterator___length_hint___impl(_PyRangeIterObject *r) +/*[clinic end generated code: output=9ba6f22b1fc23dcc input=e3eb311e99d76e43]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; return PyLong_FromLong(r->len); } -PyDoc_STRVAR(length_hint_doc, - "Private method returning an estimate of len(list(it))."); +/*[clinic input] +@critical_section +range_iterator.__reduce__ + self as r: self(type="_PyRangeIterObject *") + +Return state information for pickling. +[clinic start generated code]*/ static PyObject * -rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) +range_iterator___reduce___impl(_PyRangeIterObject *r) +/*[clinic end generated code: output=c44d53750c388415 input=75a25b7076dc2c54]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; PyObject *start=NULL, *stop=NULL, *step=NULL; PyObject *range; @@ -881,10 +912,20 @@ rangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) return NULL; } +/*[clinic input] +@critical_section +range_iterator.__setstate__ + self as r: self(type="_PyRangeIterObject *") + state: object + / + +Set state information for unpickling. +[clinic start generated code]*/ + static PyObject * -rangeiter_setstate(PyObject *op, PyObject *state) +range_iterator___setstate___impl(_PyRangeIterObject *r, PyObject *state) +/*[clinic end generated code: output=464b3cbafc2e3562 input=c8c84fab2519d200]*/ { - _PyRangeIterObject *r = (_PyRangeIterObject*)op; long index = PyLong_AsLong(state); if (index == -1 && PyErr_Occurred()) return NULL; @@ -904,13 +945,10 @@ rangeiter_dealloc(PyObject *self) _Py_FREELIST_FREE(range_iters, (_PyRangeIterObject *)self, PyObject_Free); } -PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); -PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); - static PyMethodDef rangeiter_methods[] = { - {"__length_hint__", rangeiter_len, METH_NOARGS, length_hint_doc}, - {"__reduce__", rangeiter_reduce, METH_NOARGS, reduce_doc}, - {"__setstate__", rangeiter_setstate, METH_O, setstate_doc}, + RANGE_ITERATOR___LENGTH_HINT___METHODDEF + RANGE_ITERATOR___REDUCE___METHODDEF + RANGE_ITERATOR___SETSTATE___METHODDEF {NULL, NULL} /* sentinel */ }; @@ -995,25 +1033,34 @@ fast_range_iter(long start, long stop, long step, long len) return (PyObject *)it; } -typedef struct { - PyObject_HEAD - PyObject *start; - PyObject *step; - PyObject *len; -} longrangeiterobject; +/*[clinic input] +@critical_section +longrange_iterator.__length_hint__ + self as r: self(type="longrangeiterobject *") + +Private method returning an estimate of len(list(it)). +[clinic start generated code]*/ static PyObject * -longrangeiter_len(PyObject *op, PyObject *Py_UNUSED(ignored)) +longrange_iterator___length_hint___impl(longrangeiterobject *r) +/*[clinic end generated code: output=e1bce24da7e8bfde input=ba94b050d940411e]*/ { - longrangeiterobject *r = (longrangeiterobject*)op; Py_INCREF(r->len); return r->len; } +/*[clinic input] +@critical_section +longrange_iterator.__reduce__ + self as r: self(type="longrangeiterobject *") + +Return state information for pickling. +[clinic start generated code]*/ + static PyObject * -longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) +longrange_iterator___reduce___impl(longrangeiterobject *r) +/*[clinic end generated code: output=0077f94ae2a4e99a input=2e8930e897ace086]*/ { - longrangeiterobject *r = (longrangeiterobject*)op; PyObject *product, *stop=NULL; PyObject *range; @@ -1039,15 +1086,25 @@ longrangeiter_reduce(PyObject *op, PyObject *Py_UNUSED(ignored)) range, Py_None); } +/*[clinic input] +@critical_section +longrange_iterator.__setstate__ + self as r: self(type="longrangeiterobject *") + state: object + / + +Set state information for unpickling. +[clinic start generated code]*/ + static PyObject * -longrangeiter_setstate(PyObject *op, PyObject *state) +longrange_iterator___setstate___impl(longrangeiterobject *r, PyObject *state) +/*[clinic end generated code: output=870787f0574f0da4 input=8b116de3018de824]*/ { if (!PyLong_CheckExact(state)) { PyErr_Format(PyExc_TypeError, "state must be an int, not %T", state); return NULL; } - longrangeiterobject *r = (longrangeiterobject*)op; PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp; @@ -1085,9 +1142,9 @@ longrangeiter_setstate(PyObject *op, PyObject *state) } static PyMethodDef longrangeiter_methods[] = { - {"__length_hint__", longrangeiter_len, METH_NOARGS, length_hint_doc}, - {"__reduce__", longrangeiter_reduce, METH_NOARGS, reduce_doc}, - {"__setstate__", longrangeiter_setstate, METH_O, setstate_doc}, + LONGRANGE_ITERATOR___LENGTH_HINT___METHODDEF + LONGRANGE_ITERATOR___REDUCE___METHODDEF + LONGRANGE_ITERATOR___SETSTATE___METHODDEF {NULL, NULL} /* sentinel */ }; @@ -1102,7 +1159,7 @@ longrangeiter_dealloc(PyObject *op) } static PyObject * -longrangeiter_next(PyObject *op) +longrangeiter_next_lock_held(PyObject *op) { longrangeiterobject *r = (longrangeiterobject*)op; if (PyObject_RichCompareBool(r->len, _PyLong_GetZero(), Py_GT) != 1) @@ -1123,6 +1180,16 @@ longrangeiter_next(PyObject *op) return result; } +static PyObject * +longrangeiter_next(PyObject *op) +{ + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = longrangeiter_next_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + PyTypeObject PyLongRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "longrange_iterator", /* tp_name */ diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 46489f5cd9dbae..adc85d631db7c6 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -20,15 +20,9 @@ race_top:_PyObject_TryGetInstanceAttribute race_top:PyUnstable_InterpreterFrame_GetLine race_top:write_thread_id -# gh-129068: race on shared range iterators (test_free_threading.test_zip.ZipThreading.test_threading) -race_top:rangeiter_next - # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create -# Range iteration is not thread-safe yet (issue #129068) -race_top:rangeiter_next - # List resizing happens through different paths ending in memcpy or memmove # (for efficiency), which will probably need to rewritten as explicit loops # of ptr-sized copies to be thread-safe. (Issue #129069) From 33d94abafd0c6707561493a6dd16a85ff9776f05 Mon Sep 17 00:00:00 2001 From: LloydZ <35182391+cocolato@users.noreply.github.com> Date: Fri, 19 Dec 2025 02:25:36 +0800 Subject: [PATCH 014/105] gh-134584: Eliminate redundant refcounting from _BINARY_OP_SUBSCR_LIST_INT (GH-142926) --- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_ids.h | 2 +- Include/internal/pycore_uop_metadata.h | 6 ++--- Lib/test/test_capi/test_opt.py | 18 +++++++++++++++ Python/bytecodes.c | 8 ++++--- Python/executor_cases.c.h | 26 ++++++++------------- Python/generated_cases.c.h | 28 +++++++++++++++-------- Python/optimizer_bytecodes.c | 6 +++++ Python/optimizer_cases.c.h | 16 ++++++++++--- 9 files changed, 74 insertions(+), 38 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 906ea0db0a5fe0..913359ee4bdc4f 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1338,7 +1338,7 @@ _PyOpcode_macro_expansion[256] = { [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 = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _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 = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, 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 = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_TUPLE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_TUPLE_INT, OPARG_SIMPLE, 5 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index f73aad9de1c0bf..3b7b17b5d3e53f 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -382,7 +382,7 @@ extern "C" { #define _BINARY_OP_SUBSCR_INIT_CALL_r11 575 #define _BINARY_OP_SUBSCR_INIT_CALL_r21 576 #define _BINARY_OP_SUBSCR_INIT_CALL_r31 577 -#define _BINARY_OP_SUBSCR_LIST_INT_r21 578 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 578 #define _BINARY_OP_SUBSCR_LIST_SLICE_r21 579 #define _BINARY_OP_SUBSCR_STR_INT_r21 580 #define _BINARY_OP_SUBSCR_TUPLE_INT_r21 581 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 0cc38919565bc1..99ade22c0f437a 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -1108,7 +1108,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .entries = { { -1, -1, -1 }, { -1, -1, -1 }, - { 1, 2, _BINARY_OP_SUBSCR_LIST_INT_r21 }, + { 3, 2, _BINARY_OP_SUBSCR_LIST_INT_r23 }, { -1, -1, -1 }, }, }, @@ -3422,7 +3422,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_EXTEND_r21] = _BINARY_OP_EXTEND, [_BINARY_SLICE_r31] = _BINARY_SLICE, [_STORE_SLICE_r30] = _STORE_SLICE, - [_BINARY_OP_SUBSCR_LIST_INT_r21] = _BINARY_OP_SUBSCR_LIST_INT, + [_BINARY_OP_SUBSCR_LIST_INT_r23] = _BINARY_OP_SUBSCR_LIST_INT, [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = _BINARY_OP_SUBSCR_LIST_SLICE, [_BINARY_OP_SUBSCR_STR_INT_r21] = _BINARY_OP_SUBSCR_STR_INT, [_GUARD_NOS_TUPLE_r02] = _GUARD_NOS_TUPLE, @@ -3930,7 +3930,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_SUBSCR_INIT_CALL_r21] = "_BINARY_OP_SUBSCR_INIT_CALL_r21", [_BINARY_OP_SUBSCR_INIT_CALL_r31] = "_BINARY_OP_SUBSCR_INIT_CALL_r31", [_BINARY_OP_SUBSCR_LIST_INT] = "_BINARY_OP_SUBSCR_LIST_INT", - [_BINARY_OP_SUBSCR_LIST_INT_r21] = "_BINARY_OP_SUBSCR_LIST_INT_r21", + [_BINARY_OP_SUBSCR_LIST_INT_r23] = "_BINARY_OP_SUBSCR_LIST_INT_r23", [_BINARY_OP_SUBSCR_LIST_SLICE] = "_BINARY_OP_SUBSCR_LIST_SLICE", [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = "_BINARY_OP_SUBSCR_LIST_SLICE_r21", [_BINARY_OP_SUBSCR_STR_INT] = "_BINARY_OP_SUBSCR_STR_INT", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 6f1b115b31257f..a35dea8557ddbb 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2988,6 +2988,24 @@ class Obj: for _ in range(TIER2_THRESHOLD+1): obj.attr = EvilAttr(obj.__dict__) + def test_binary_subscr_list_int(self): + def testfunc(n): + l = [1] + x = 0 + for _ in range(n): + y = l[0] + x += y + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_BINARY_OP_SUBSCR_LIST_INT", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertNotIn("_POP_TOP_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) def global_identity(x): return x diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3e3b3d2f446d33..1c6d0bb9cdf256 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -893,9 +893,9 @@ dummy_func( macro(STORE_SLICE) = _SPECIALIZE_STORE_SLICE + _STORE_SLICE; macro(BINARY_OP_SUBSCR_LIST_INT) = - _GUARD_TOS_INT + _GUARD_NOS_LIST + unused/5 + _BINARY_OP_SUBSCR_LIST_INT; + _GUARD_TOS_INT + _GUARD_NOS_LIST + unused/5 + _BINARY_OP_SUBSCR_LIST_INT + _POP_TOP_INT + POP_TOP; - op(_BINARY_OP_SUBSCR_LIST_INT, (list_st, sub_st -- res)) { + op(_BINARY_OP_SUBSCR_LIST_INT, (list_st, sub_st -- res, ls, ss)) { PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *list = PyStackRef_AsPyObjectBorrow(list_st); @@ -918,7 +918,9 @@ dummy_func( res = PyStackRef_FromPyObjectNew(res_o); #endif STAT_INC(BINARY_OP, hit); - DECREF_INPUTS(); + ls = list_st; + ss = sub_st; + INPUTS_DEAD(); } macro(BINARY_OP_SUBSCR_LIST_SLICE) = diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b7ee752cd44e16..36ae739e58d6c5 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4544,12 +4544,14 @@ break; } - case _BINARY_OP_SUBSCR_LIST_INT_r21: { + case _BINARY_OP_SUBSCR_LIST_INT_r23: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef list_st; _PyStackRef res; + _PyStackRef ls; + _PyStackRef ss; _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; sub_st = _stack_item_1; @@ -4600,23 +4602,13 @@ stack_pointer += 2; #endif STAT_INC(BINARY_OP, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = list_st; - list_st = res; - stack_pointer[-2] = list_st; - PyStackRef_CLOSE(tmp); - tmp = sub_st; - sub_st = PyStackRef_NULL; - stack_pointer[-1] = sub_st; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + ls = list_st; + ss = sub_st; + _tos_cache2 = ss; + _tos_cache1 = ls; _tos_cache0 = res; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -1; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 28dc7b25f0d2cc..0c0256bcc3b753 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -764,6 +764,8 @@ _PyStackRef list_st; _PyStackRef sub_st; _PyStackRef res; + _PyStackRef ls; + _PyStackRef ss; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -822,18 +824,24 @@ res = PyStackRef_FromPyObjectNew(res_o); #endif STAT_INC(BINARY_OP, hit); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = list_st; - list_st = res; - stack_pointer[-2] = list_st; - PyStackRef_CLOSE(tmp); - tmp = sub_st; - sub_st = PyStackRef_NULL; - stack_pointer[-1] = sub_st; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); + ls = list_st; + ss = sub_st; + } + // _POP_TOP_INT + { + value = ss; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP + { + value = ls; + stack_pointer[-2] = res; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); } DISPATCH(); } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e3921054f7cb43..9578b56e707393 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1417,6 +1417,12 @@ dummy_func(void) { } } + op(_BINARY_OP_SUBSCR_LIST_INT, (list_st, sub_st -- res, ls, ss)) { + res = sym_new_unknown(ctx); + ls = list_st; + ss = sub_st; + } + // END BYTECODES // diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 32d60c76a4f3ce..f047cd82d4c5e7 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -763,11 +763,21 @@ } case _BINARY_OP_SUBSCR_LIST_INT: { + JitOptRef sub_st; + JitOptRef list_st; JitOptRef res; - res = sym_new_not_null(ctx); - CHECK_STACK_BOUNDS(-1); + JitOptRef ls; + JitOptRef ss; + sub_st = stack_pointer[-1]; + list_st = stack_pointer[-2]; + res = sym_new_unknown(ctx); + ls = list_st; + ss = sub_st; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[-1] = ls; + stack_pointer[0] = ss; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } From e79c39101a9f55882f54df0bb3ecfa23238692de Mon Sep 17 00:00:00 2001 From: Ethan Furman Date: Thu, 18 Dec 2025 10:31:37 -0800 Subject: [PATCH 015/105] gh-118342: [Enum] update docs (GH-137290) Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/library/enum.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst index a8a7e671aadca2..0da27ba8e78284 100644 --- a/Doc/library/enum.rst +++ b/Doc/library/enum.rst @@ -947,12 +947,13 @@ Utilities and Decorators the member's name. Care must be taken if mixing *auto()* with manually specified values. - *auto* instances are only resolved when at the top level of an assignment: + *auto* instances are only resolved when at the top level of an assignment, either by + itself or as part of a tuple: * ``FIRST = auto()`` will work (auto() is replaced with ``1``); * ``SECOND = auto(), -2`` will work (auto is replaced with ``2``, so ``2, -2`` is used to create the ``SECOND`` enum member; - * ``THREE = [auto(), -3]`` will *not* work (``, -3`` is used to + * ``THREE = [auto(), -3]`` will *not* work (``[, -3]`` is used to create the ``THREE`` enum member) .. versionchanged:: 3.11.1 From 1391ee664c8f019996e0cbf658e12fa38abd211d Mon Sep 17 00:00:00 2001 From: Savannah Ostrowski Date: Thu, 18 Dec 2025 13:29:54 -0800 Subject: [PATCH 016/105] GH-134584: Remove redundant refcount for `BINARY_OP_SUBSCR_STR_INT` (#142844) --- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_ids.h | 2 +- Include/internal/pycore_uop_metadata.h | 8 ++++---- Lib/test/test_capi/test_opt.py | 20 ++++++++++++++++++ Python/bytecodes.c | 10 ++++----- Python/executor_cases.c.h | 16 +++++++-------- Python/generated_cases.c.h | 25 ++++++++++++++++------- Python/optimizer_bytecodes.c | 4 +++- Python/optimizer_cases.c.h | 14 +++++++++++-- 9 files changed, 72 insertions(+), 29 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 913359ee4bdc4f..92423fe51408fc 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1340,7 +1340,7 @@ _PyOpcode_macro_expansion[256] = { [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _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 = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 } } }, + [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_TUPLE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_TUPLE_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBTRACT_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 3b7b17b5d3e53f..e9851b767bc835 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -384,7 +384,7 @@ extern "C" { #define _BINARY_OP_SUBSCR_INIT_CALL_r31 577 #define _BINARY_OP_SUBSCR_LIST_INT_r23 578 #define _BINARY_OP_SUBSCR_LIST_SLICE_r21 579 -#define _BINARY_OP_SUBSCR_STR_INT_r21 580 +#define _BINARY_OP_SUBSCR_STR_INT_r23 580 #define _BINARY_OP_SUBSCR_TUPLE_INT_r21 581 #define _BINARY_OP_SUBTRACT_FLOAT_r03 582 #define _BINARY_OP_SUBTRACT_FLOAT_r13 583 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 99ade22c0f437a..3a6bf7b3d76a8f 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -119,7 +119,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_SUBSCR_LIST_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, - [_BINARY_OP_SUBSCR_STR_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_BINARY_OP_SUBSCR_STR_INT] = HAS_DEOPT_FLAG, [_GUARD_NOS_TUPLE] = HAS_EXIT_FLAG, [_GUARD_TOS_TUPLE] = HAS_EXIT_FLAG, [_BINARY_OP_SUBSCR_TUPLE_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, @@ -1126,7 +1126,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .entries = { { -1, -1, -1 }, { -1, -1, -1 }, - { 1, 2, _BINARY_OP_SUBSCR_STR_INT_r21 }, + { 3, 2, _BINARY_OP_SUBSCR_STR_INT_r23 }, { -1, -1, -1 }, }, }, @@ -3424,7 +3424,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_STORE_SLICE_r30] = _STORE_SLICE, [_BINARY_OP_SUBSCR_LIST_INT_r23] = _BINARY_OP_SUBSCR_LIST_INT, [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = _BINARY_OP_SUBSCR_LIST_SLICE, - [_BINARY_OP_SUBSCR_STR_INT_r21] = _BINARY_OP_SUBSCR_STR_INT, + [_BINARY_OP_SUBSCR_STR_INT_r23] = _BINARY_OP_SUBSCR_STR_INT, [_GUARD_NOS_TUPLE_r02] = _GUARD_NOS_TUPLE, [_GUARD_NOS_TUPLE_r12] = _GUARD_NOS_TUPLE, [_GUARD_NOS_TUPLE_r22] = _GUARD_NOS_TUPLE, @@ -3934,7 +3934,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_SUBSCR_LIST_SLICE] = "_BINARY_OP_SUBSCR_LIST_SLICE", [_BINARY_OP_SUBSCR_LIST_SLICE_r21] = "_BINARY_OP_SUBSCR_LIST_SLICE_r21", [_BINARY_OP_SUBSCR_STR_INT] = "_BINARY_OP_SUBSCR_STR_INT", - [_BINARY_OP_SUBSCR_STR_INT_r21] = "_BINARY_OP_SUBSCR_STR_INT_r21", + [_BINARY_OP_SUBSCR_STR_INT_r23] = "_BINARY_OP_SUBSCR_STR_INT_r23", [_BINARY_OP_SUBSCR_TUPLE_INT] = "_BINARY_OP_SUBSCR_TUPLE_INT", [_BINARY_OP_SUBSCR_TUPLE_INT_r21] = "_BINARY_OP_SUBSCR_TUPLE_INT_r21", [_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index a35dea8557ddbb..88ac1664fe5ddf 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1877,6 +1877,26 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_UNICODE", uops) self.assertIn("_BINARY_OP_ADD_UNICODE", uops) + def test_binary_op_subscr_str_int(self): + def testfunc(n): + x = 0 + s = "hello" + for _ in range(n): + c = s[1] # _BINARY_OP_SUBSCR_STR_INT + if c == 'e': + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_SUBSCR_STR_INT", uops) + self.assertIn("_COMPARE_OP_STR", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertNotIn("_POP_TOP", uops) + self.assertNotIn("_POP_TOP_INT", uops) + def test_call_type_1_guards_removed(self): def testfunc(n): x = 0 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1c6d0bb9cdf256..4ce7968ddc2929 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -941,9 +941,9 @@ dummy_func( } macro(BINARY_OP_SUBSCR_STR_INT) = - _GUARD_TOS_INT + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_SUBSCR_STR_INT; + _GUARD_TOS_INT + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_SUBSCR_STR_INT + _POP_TOP_INT + POP_TOP; - op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res)) { + op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res, s, i)) { PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); PyObject *str = PyStackRef_AsPyObjectBorrow(str_st); @@ -958,9 +958,9 @@ dummy_func( assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - DEAD(sub_st); - PyStackRef_CLOSE(str_st); + INPUTS_DEAD(); + s = str_st; + i = sub_st; res = PyStackRef_FromPyObjectBorrow(res_o); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 36ae739e58d6c5..74bd939c87d4ec 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4661,12 +4661,14 @@ break; } - case _BINARY_OP_SUBSCR_STR_INT_r21: { + case _BINARY_OP_SUBSCR_STR_INT_r23: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef sub_st; _PyStackRef str_st; _PyStackRef res; + _PyStackRef s; + _PyStackRef i; _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; sub_st = _stack_item_1; @@ -4701,15 +4703,13 @@ assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(str_st); - stack_pointer = _PyFrame_GetStackPointer(frame); + s = str_st; + i = sub_st; res = PyStackRef_FromPyObjectBorrow(res_o); + _tos_cache2 = i; + _tos_cache1 = s; _tos_cache0 = res; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(1); + SET_CURRENT_CACHED_VALUES(3); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 0c0256bcc3b753..4482bb08a132f9 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -934,6 +934,8 @@ _PyStackRef str_st; _PyStackRef sub_st; _PyStackRef res; + _PyStackRef s; + _PyStackRef i; // _GUARD_TOS_INT { value = stack_pointer[-1]; @@ -983,17 +985,26 @@ assert(c < 128); STAT_INC(BINARY_OP, hit); PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c]; - PyStackRef_CLOSE_SPECIALIZED(sub_st, _PyLong_ExactDealloc); - stack_pointer += -2; + s = str_st; + i = sub_st; + res = PyStackRef_FromPyObjectBorrow(res_o); + } + // _POP_TOP_INT + { + value = i; + assert(PyLong_CheckExact(PyStackRef_AsPyObjectBorrow(value))); + PyStackRef_CLOSE_SPECIALIZED(value, _PyLong_ExactDealloc); + } + // _POP_TOP + { + value = s; + stack_pointer[-2] = res; + stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(str_st); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectBorrow(res_o); } - stack_pointer[0] = res; - stack_pointer += 1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 9578b56e707393..f36139db954cb8 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -329,8 +329,10 @@ dummy_func(void) { ctx->done = true; } - op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res)) { + op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res, s, i)) { res = sym_new_type(ctx, &PyUnicode_Type); + s = str_st; + i = sub_st; } op(_BINARY_OP_SUBSCR_TUPLE_INT, (tuple_st, sub_st -- res)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index f047cd82d4c5e7..69a2a32e4f15df 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -793,11 +793,21 @@ } case _BINARY_OP_SUBSCR_STR_INT: { + JitOptRef sub_st; + JitOptRef str_st; JitOptRef res; + JitOptRef s; + JitOptRef i; + sub_st = stack_pointer[-1]; + str_st = stack_pointer[-2]; res = sym_new_type(ctx, &PyUnicode_Type); - CHECK_STACK_BOUNDS(-1); + s = str_st; + i = sub_st; + CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[-1] = s; + stack_pointer[0] = i; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } From 220f0b107776391201a399c54dd01692c36fcdf4 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Fri, 19 Dec 2025 16:02:23 +0800 Subject: [PATCH 017/105] gh-142560: prevent use-after-free in search-like methods by exporting buffer in bytearray (#142938) --- Lib/test/test_bytes.py | 31 +++++ ...-12-11-22-59-33.gh-issue-142560.GkJrkk.rst | 1 + Objects/bytearrayobject.c | 113 +++++++++++------- 3 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-11-22-59-33.gh-issue-142560.GkJrkk.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index a55ec6cf3b8353..21be61e4fec720 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -2060,6 +2060,37 @@ def __index__(self): self.assertEqual(instance.ba[0], ord("?"), "Assigned bytearray not altered") self.assertEqual(instance.new_ba, bytearray(0x180), "Wrong object altered") + def test_search_methods_reentrancy_raises_buffererror(self): + # gh-142560: Raise BufferError if buffer mutates during search arg conversion. + class Evil: + def __init__(self, ba): + self.ba = ba + def __buffer__(self, flags): + self.ba.clear() + return memoryview(self.ba) + def __release_buffer__(self, view: memoryview) -> None: + view.release() + def __index__(self): + self.ba.clear() + return ord("A") + + def make_case(): + ba = bytearray(b"A") + return ba, Evil(ba) + + for name in ("find", "count", "index", "rindex", "rfind"): + ba, evil = make_case() + with self.subTest(name): + with self.assertRaises(BufferError): + getattr(ba, name)(evil) + + ba, evil = make_case() + with self.assertRaises(BufferError): + evil in ba + with self.assertRaises(BufferError): + ba.split(evil) + with self.assertRaises(BufferError): + ba.rsplit(evil) class AssortedBytesTest(unittest.TestCase): # diff --git a/Misc/NEWS.d/next/Library/2025-12-11-22-59-33.gh-issue-142560.GkJrkk.rst b/Misc/NEWS.d/next/Library/2025-12-11-22-59-33.gh-issue-142560.GkJrkk.rst new file mode 100644 index 00000000000000..9c0657214b0751 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-11-22-59-33.gh-issue-142560.GkJrkk.rst @@ -0,0 +1 @@ +Fix use-after-free in :class:`bytearray` search-like methods (:meth:`~bytearray.find`, :meth:`~bytearray.count`, :meth:`~bytearray.index`, :meth:`~bytearray.rindex`, and :meth:`~bytearray.rfind`) by marking the storage as exported which causes reallocation attempts to raise :exc:`BufferError`. For :func:`~operator.contains`, :meth:`~bytearray.split`, and :meth:`~bytearray.rsplit` the :ref:`buffer protocol ` is used for this. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 25cc0bfcbaba45..338c71ad38f7aa 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -90,6 +90,25 @@ bytearray_releasebuffer(PyObject *self, Py_buffer *view) Py_END_CRITICAL_SECTION(); } +typedef PyObject* (*_ba_bytes_op)(const char *buf, Py_ssize_t len, + PyObject *sub, Py_ssize_t start, + Py_ssize_t end); + +static PyObject * +_bytearray_with_buffer(PyByteArrayObject *self, _ba_bytes_op op, PyObject *sub, + Py_ssize_t start, Py_ssize_t end) +{ + PyObject *res; + + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + + /* Increase exports to prevent bytearray storage from changing during op. */ + self->ob_exports++; + res = op(PyByteArray_AS_STRING(self), Py_SIZE(self), sub, start, end); + self->ob_exports--; + return res; +} + static int _canresize(PyByteArrayObject *self) { @@ -1248,8 +1267,7 @@ bytearray_find_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=413e1cab2ae87da0 input=df3aa94840d893a7]*/ { - return _Py_bytes_find(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - sub, start, end); + return _bytearray_with_buffer(self, _Py_bytes_find, sub, start, end); } /*[clinic input] @@ -1265,8 +1283,7 @@ bytearray_count_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=a21ee2692e4f1233 input=e8fcdca8272857e0]*/ { - return _Py_bytes_count(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - sub, start, end); + return _bytearray_with_buffer(self, _Py_bytes_count, sub, start, end); } /*[clinic input] @@ -1314,8 +1331,7 @@ bytearray_index_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=067a1e78efc672a7 input=c37f177cfee19fe4]*/ { - return _Py_bytes_index(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - sub, start, end); + return _bytearray_with_buffer(self, _Py_bytes_index, sub, start, end); } /*[clinic input] @@ -1333,8 +1349,7 @@ bytearray_rfind_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=51bf886f932b283c input=1265b11c437d2750]*/ { - return _Py_bytes_rfind(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - sub, start, end); + return _bytearray_with_buffer(self, _Py_bytes_rfind, sub, start, end); } /*[clinic input] @@ -1352,18 +1367,22 @@ bytearray_rindex_impl(PyByteArrayObject *self, PyObject *sub, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=38e1cf66bafb08b9 input=7d198b3d6b0a62ce]*/ { - return _Py_bytes_rindex(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - sub, start, end); + return _bytearray_with_buffer(self, _Py_bytes_rindex, sub, start, end); } static int bytearray_contains(PyObject *self, PyObject *arg) { - int ret; + int ret = -1; Py_BEGIN_CRITICAL_SECTION(self); - ret = _Py_bytes_contains(PyByteArray_AS_STRING(self), + PyByteArrayObject *ba = _PyByteArray_CAST(self); + + /* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */ + ba->ob_exports++; + ret = _Py_bytes_contains(PyByteArray_AS_STRING(ba), PyByteArray_GET_SIZE(self), arg); + ba->ob_exports--; Py_END_CRITICAL_SECTION(); return ret; } @@ -1390,8 +1409,7 @@ bytearray_startswith_impl(PyByteArrayObject *self, PyObject *subobj, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=a3d9b6d44d3662a6 input=93f9ffee684f109a]*/ { - return _Py_bytes_startswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - subobj, start, end); + return _bytearray_with_buffer(self, _Py_bytes_startswith, subobj, start, end); } /*[clinic input] @@ -1416,8 +1434,7 @@ bytearray_endswith_impl(PyByteArrayObject *self, PyObject *subobj, Py_ssize_t start, Py_ssize_t end) /*[clinic end generated code: output=e75ea8c227954caa input=d158b030a11d0b06]*/ { - return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), - subobj, start, end); + return _bytearray_with_buffer(self, _Py_bytes_endswith, subobj, start, end); } /*[clinic input] @@ -1782,26 +1799,32 @@ bytearray_split_impl(PyByteArrayObject *self, PyObject *sep, Py_ssize_t maxsplit) /*[clinic end generated code: output=833e2cf385d9a04d input=dd9f6e2910cc3a34]*/ { - Py_ssize_t len = PyByteArray_GET_SIZE(self), n; - const char *s = PyByteArray_AS_STRING(self), *sub; - PyObject *list; - Py_buffer vsub; + PyObject *list = NULL; + + /* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */ + self->ob_exports++; + const char *sbuf = PyByteArray_AS_STRING(self); + Py_ssize_t slen = PyByteArray_GET_SIZE((PyObject *)self); if (maxsplit < 0) maxsplit = PY_SSIZE_T_MAX; - if (sep == Py_None) - return stringlib_split_whitespace((PyObject*) self, s, len, maxsplit); + if (sep == Py_None) { + list = stringlib_split_whitespace((PyObject*)self, sbuf, slen, maxsplit); + goto done; + } - if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) - return NULL; - sub = vsub.buf; - n = vsub.len; + Py_buffer vsub; + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) { + goto done; + } - list = stringlib_split( - (PyObject*) self, s, len, sub, n, maxsplit - ); + list = stringlib_split((PyObject*)self, sbuf, slen, + (const char *)vsub.buf, vsub.len, maxsplit); PyBuffer_Release(&vsub); + +done: + self->ob_exports--; return list; } @@ -1900,26 +1923,32 @@ bytearray_rsplit_impl(PyByteArrayObject *self, PyObject *sep, Py_ssize_t maxsplit) /*[clinic end generated code: output=a55e0b5a03cb6190 input=60e9abf305128ff4]*/ { - Py_ssize_t len = PyByteArray_GET_SIZE(self), n; - const char *s = PyByteArray_AS_STRING(self), *sub; - PyObject *list; - Py_buffer vsub; + PyObject *list = NULL; + + /* Increase exports to prevent bytearray storage from changing during _Py_bytes_contains(). */ + self->ob_exports++; + const char *sbuf = PyByteArray_AS_STRING(self); + Py_ssize_t slen = PyByteArray_GET_SIZE((PyObject *)self); if (maxsplit < 0) maxsplit = PY_SSIZE_T_MAX; - if (sep == Py_None) - return stringlib_rsplit_whitespace((PyObject*) self, s, len, maxsplit); + if (sep == Py_None) { + list = stringlib_rsplit_whitespace((PyObject*)self, sbuf, slen, maxsplit); + goto done; + } - if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) - return NULL; - sub = vsub.buf; - n = vsub.len; + Py_buffer vsub; + if (PyObject_GetBuffer(sep, &vsub, PyBUF_SIMPLE) != 0) { + goto done; + } - list = stringlib_rsplit( - (PyObject*) self, s, len, sub, n, maxsplit - ); + list = stringlib_rsplit((PyObject*)self, sbuf, slen, + (const char *)vsub.buf, vsub.len, maxsplit); PyBuffer_Release(&vsub); + +done: + self->ob_exports--; return list; } From 610aabfef2f90dc1a274703779615aa5b7fbbb3a Mon Sep 17 00:00:00 2001 From: Andrej Date: Fri, 19 Dec 2025 00:29:35 -0800 Subject: [PATCH 018/105] gh-142527: Docs: Clarify that random.seed() discards the sign of an integer input (#142483) If *a* is an integer, the sign of *a* is discarded in the C source code. Clarify this behavior to prevent foot guns, where a common use case might naively assume that flipping the sign will produce different sequences (e.g. for a train/test split of a synthetic data generator in machine learning). Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> --- Doc/library/random.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/random.rst b/Doc/library/random.rst index 4e55e301b89095..6bddf575a809a1 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -78,7 +78,7 @@ Bookkeeping functions instead of the system time (see the :func:`os.urandom` function for details on availability). - If *a* is an int, it is used directly. + If *a* is an int, its absolute value is used directly. With version 2 (the default), a :class:`str`, :class:`bytes`, or :class:`bytearray` object gets converted to an :class:`int` and all of its bits are used. From 4aef13832521b4e7785c9643f6a995c92b4a691d Mon Sep 17 00:00:00 2001 From: Rogdham <3994389+Rogdham@users.noreply.github.com> Date: Fri, 19 Dec 2025 13:44:03 +0100 Subject: [PATCH 019/105] gh-136282: Configparser: create unnamed sections via mapping protocol access (GH-136313) --- Lib/configparser.py | 3 ++- Lib/test/test_configparser.py | 13 +++++++++++++ .../2025-07-05-08-30-07.gh-issue-136282.K3JKyD.rst | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-07-05-08-30-07.gh-issue-136282.K3JKyD.rst diff --git a/Lib/configparser.py b/Lib/configparser.py index 18af1eadaad111..d435a5c2fe0da2 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -794,7 +794,8 @@ def read_dict(self, dictionary, source=''): """ elements_added = set() for section, keys in dictionary.items(): - section = str(section) + if section is not UNNAMED_SECTION: + section = str(section) try: self.add_section(section) except (DuplicateSectionError, ValueError): diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index e7364e18742c16..1bfb53ccbb1398 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -2215,6 +2215,16 @@ def test_add_section(self): cfg.add_section(configparser.UNNAMED_SECTION) cfg.set(configparser.UNNAMED_SECTION, 'a', '1') self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) + output = io.StringIO() + cfg.write(output) + self.assertEqual(output.getvalue(), 'a = 1\n\n') + + cfg = configparser.ConfigParser(allow_unnamed_section=True) + cfg[configparser.UNNAMED_SECTION] = {'a': '1'} + self.assertEqual('1', cfg[configparser.UNNAMED_SECTION]['a']) + output = io.StringIO() + cfg.write(output) + self.assertEqual(output.getvalue(), 'a = 1\n\n') def test_disabled_error(self): with self.assertRaises(configparser.MissingSectionHeaderError): @@ -2223,6 +2233,9 @@ def test_disabled_error(self): with self.assertRaises(configparser.UnnamedSectionDisabledError): configparser.ConfigParser().add_section(configparser.UNNAMED_SECTION) + with self.assertRaises(configparser.UnnamedSectionDisabledError): + configparser.ConfigParser()[configparser.UNNAMED_SECTION] = {'a': '1'} + def test_multiple_configs(self): cfg = configparser.ConfigParser(allow_unnamed_section=True) cfg.read_string('a = 1') diff --git a/Misc/NEWS.d/next/Library/2025-07-05-08-30-07.gh-issue-136282.K3JKyD.rst b/Misc/NEWS.d/next/Library/2025-07-05-08-30-07.gh-issue-136282.K3JKyD.rst new file mode 100644 index 00000000000000..b5589b47716c70 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-05-08-30-07.gh-issue-136282.K3JKyD.rst @@ -0,0 +1,2 @@ +Add support for :const:`~configparser.UNNAMED_SECTION` when creating a +section via the mapping protocol access From 685272eb8abb3b5ad73f6251f56990229f42456e Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Fri, 19 Dec 2025 14:39:41 +0000 Subject: [PATCH 020/105] JIT: Rename trampoline.c to shim.c (#142974) --- Include/internal/pycore_ceval.h | 2 +- Python/ceval.c | 4 ++-- Python/jit.c | 18 +++++++++--------- Python/pystate.c | 2 +- Tools/jit/_targets.py | 4 ++-- Tools/jit/_writer.py | 4 ++-- Tools/jit/{trampoline.c => shim.c} | 0 7 files changed, 17 insertions(+), 17 deletions(-) rename Tools/jit/{trampoline.c => shim.c} (100%) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index af53f2e7d6f73e..bf34c55cd783e4 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -123,7 +123,7 @@ _PyEval_EvalFrame(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwfl #ifdef _Py_TIER2 #ifdef _Py_JIT -_Py_CODEUNIT *_Py_LazyJitTrampoline( +_Py_CODEUNIT *_Py_LazyJitShim( struct _PyExecutorObject *current_executor, _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate ); diff --git a/Python/ceval.c b/Python/ceval.c index 90ae0b022e3958..cf86d5484f0d6e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1601,7 +1601,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } #ifdef _Py_TIER2 #ifdef _Py_JIT -_PyJitEntryFuncPtr _Py_jit_entry = _Py_LazyJitTrampoline; +_PyJitEntryFuncPtr _Py_jit_entry = _Py_LazyJitShim; #else _PyJitEntryFuncPtr _Py_jit_entry = _PyTier2Interpreter; #endif @@ -1617,7 +1617,7 @@ _PyTier2Interpreter( const _PyUOpInstruction *next_uop; int oparg; /* Set up "jit" state after entry from tier 1. - * This mimics what the jit trampoline function does. */ + * This mimics what the jit shim function does. */ tstate->jit_exit = NULL; _PyStackRef _tos_cache0 = PyStackRef_ZERO_BITS; _PyStackRef _tos_cache1 = PyStackRef_ZERO_BITS; diff --git a/Python/jit.c b/Python/jit.c index 7660f6f9beac89..4ce90edf73a8cb 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -672,20 +672,20 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction trace[], siz return 0; } -/* One-off compilation of the jit entry trampoline +/* One-off compilation of the jit entry shim * We compile this once only as it effectively a normal * function, but we need to use the JIT because it needs * to understand the jit-specific calling convention. */ static _PyJitEntryFuncPtr -compile_trampoline(void) +compile_shim(void) { _PyExecutorObject dummy; const StencilGroup *group; size_t code_size = 0; size_t data_size = 0; jit_state state = {0}; - group = &trampoline; + group = &shim; code_size += group->code_size; data_size += group->data_size; combine_symbol_mask(group->trampoline_mask, state.trampolines.mask); @@ -707,7 +707,7 @@ compile_trampoline(void) // Compile the shim, which handles converting between the native // calling convention and the calling convention used by jitted code // (which may be different for efficiency reasons). - group = &trampoline; + group = &shim; group->emit(code, data, &dummy, NULL, &state); code += group->code_size; data += group->data_size; @@ -723,17 +723,17 @@ compile_trampoline(void) static PyMutex lazy_jit_mutex = { 0 }; _Py_CODEUNIT * -_Py_LazyJitTrampoline( +_Py_LazyJitShim( _PyExecutorObject *executor, _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate ) { PyMutex_Lock(&lazy_jit_mutex); - if (_Py_jit_entry == _Py_LazyJitTrampoline) { - _PyJitEntryFuncPtr trampoline = compile_trampoline(); - if (trampoline == NULL) { + if (_Py_jit_entry == _Py_LazyJitShim) { + _PyJitEntryFuncPtr shim = compile_shim(); + if (shim == NULL) { PyMutex_Unlock(&lazy_jit_mutex); Py_FatalError("Cannot allocate core JIT code"); } - _Py_jit_entry = trampoline; + _Py_jit_entry = shim; } PyMutex_Unlock(&lazy_jit_mutex); return _Py_jit_entry(executor, frame, stack_pointer, tstate); diff --git a/Python/pystate.c b/Python/pystate.c index 7ea8ef91f107a9..cf55297cf8d94e 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -490,7 +490,7 @@ static inline int check_interpreter_whence(long); #endif extern _Py_CODEUNIT * -_Py_LazyJitTrampoline( +_Py_LazyJitShim( struct _PyExecutorObject *exec, _PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate ); diff --git a/Tools/jit/_targets.py b/Tools/jit/_targets.py index 5895e91c3c44ce..39be353ec30858 100644 --- a/Tools/jit/_targets.py +++ b/Tools/jit/_targets.py @@ -204,8 +204,8 @@ async def _build_stencils(self) -> dict[str, _stencils.StencilGroup]: with tempfile.TemporaryDirectory() as tempdir: work = pathlib.Path(tempdir).resolve() async with asyncio.TaskGroup() as group: - coro = self._compile("trampoline", TOOLS_JIT / "trampoline.c", work) - tasks.append(group.create_task(coro, name="trampoline")) + coro = self._compile("shim", TOOLS_JIT / "shim.c", work) + tasks.append(group.create_task(coro, name="shim")) template = TOOLS_JIT_TEMPLATE_C.read_text() for case, opname in cases_and_opnames: # Write out a copy of the template with *only* this case diff --git a/Tools/jit/_writer.py b/Tools/jit/_writer.py index 3a59ffce7a2c45..5fd9a2ee2d6e58 100644 --- a/Tools/jit/_writer.py +++ b/Tools/jit/_writer.py @@ -23,11 +23,11 @@ def _dump_footer( yield " symbol_mask got_mask;" yield "} StencilGroup;" yield "" - yield f"static const StencilGroup trampoline = {groups['trampoline'].as_c('trampoline')};" + yield f"static const StencilGroup shim = {groups['shim'].as_c('shim')};" yield "" yield "static const StencilGroup stencil_groups[MAX_UOP_REGS_ID + 1] = {" for opname, group in sorted(groups.items()): - if opname == "trampoline": + if opname == "shim": continue yield f" [{opname}] = {group.as_c(opname)}," yield "};" diff --git a/Tools/jit/trampoline.c b/Tools/jit/shim.c similarity index 100% rename from Tools/jit/trampoline.c rename to Tools/jit/shim.c From 049c2526bffddf94495b7c0d2d788ac9faf4078a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 19 Dec 2025 17:48:34 +0100 Subject: [PATCH 021/105] gh-134160: Start "Extending and embedding" with a Diataxis-style tutorial (GH-142314) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Co-authored-by: Éric Co-authored-by: Daniele Nicolodi Co-authored-by: Peter Bierma --- Doc/c-api/intro.rst | 40 ++ Doc/extending/extending.rst | 421 ++---------- Doc/extending/first-extension-module.rst | 667 ++++++++++++++++++++ Doc/extending/index.rst | 86 ++- Doc/includes/capi-extension/spammodule-01.c | 55 ++ 5 files changed, 885 insertions(+), 384 deletions(-) create mode 100644 Doc/extending/first-extension-module.rst create mode 100644 Doc/includes/capi-extension/spammodule-01.c diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index bb94bcb86a7899..5e90d9b7bc91ed 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -107,6 +107,46 @@ header files properly declare the entry points to be ``extern "C"``. As a result there is no need to do anything special to use the API from C++. +.. _capi-system-includes: + +System includes +--------------- + + :file:`Python.h` includes several standard header files. + C extensions should include the standard headers that they use, + and should not rely on these implicit includes. + The implicit includes are: + + * ```` + * ```` (on Windows) + * ```` + * ```` + * ```` + * ```` + * ```` + * ```` (if present) + + The following are included for backwards compatibility, unless using + :ref:`Limited API ` 3.13 or newer: + + * ```` + * ```` (on POSIX) + + The following are included for backwards compatibility, unless using + :ref:`Limited API ` 3.11 or newer: + + * ```` + * ```` + * ```` + * ```` + +.. note:: + + Since Python may define some pre-processor definitions which affect the standard + headers on some systems, you *must* include :file:`Python.h` before any standard + headers are included. + + Useful macros ============= diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst index f9b65643dfe888..c0066d315d092b 100644 --- a/Doc/extending/extending.rst +++ b/Doc/extending/extending.rst @@ -3,154 +3,20 @@ .. _extending-intro: -****************************** -Extending Python with C or C++ -****************************** +******************************** +Using the C API: Assorted topics +******************************** -It is quite easy to add new built-in modules to Python, if you know how to -program in C. Such :dfn:`extension modules` can do two things that can't be -done directly in Python: they can implement new built-in object types, and they -can call C library functions and system calls. - -To support extensions, the Python API (Application Programmers Interface) -defines a set of functions, macros and variables that provide access to most -aspects of the Python run-time system. The Python API is incorporated in a C -source file by including the header ``"Python.h"``. - -The compilation of an extension module depends on its intended use as well as on -your system setup; details are given in later chapters. - -.. note:: - - The C extension interface is specific to CPython, and extension modules do - not work on other Python implementations. In many cases, it is possible to - avoid writing C extensions and preserve portability to other implementations. - For example, if your use case is calling C library functions or system calls, - you should consider using the :mod:`ctypes` module or the `cffi - `_ library rather than writing - custom C code. - These modules let you write Python code to interface with C code and are more - portable between implementations of Python than writing and compiling a C - extension module. - - -.. _extending-simpleexample: - -A Simple Example -================ - -Let's create an extension module called ``spam`` (the favorite food of Monty -Python fans...) and let's say we want to create a Python interface to the C -library function :c:func:`system` [#]_. This function takes a null-terminated -character string as argument and returns an integer. We want this function to -be callable from Python as follows: - -.. code-block:: pycon - - >>> import spam - >>> status = spam.system("ls -l") - -Begin by creating a file :file:`spammodule.c`. (Historically, if a module is -called ``spam``, the C file containing its implementation is called -:file:`spammodule.c`; if the module name is very long, like ``spammify``, the -module name can be just :file:`spammify.c`.) - -The first two lines of our file can be:: - - #define PY_SSIZE_T_CLEAN - #include - -which pulls in the Python API (you can add a comment describing the purpose of -the module and a copyright notice if you like). - -.. note:: - - Since Python may define some pre-processor definitions which affect the standard - headers on some systems, you *must* include :file:`Python.h` before any standard - headers are included. - - ``#define PY_SSIZE_T_CLEAN`` was used to indicate that ``Py_ssize_t`` should be - used in some APIs instead of ``int``. - It is not necessary since Python 3.13, but we keep it here for backward compatibility. - See :ref:`arg-parsing-string-and-buffers` for a description of this macro. - -All user-visible symbols defined by :file:`Python.h` have a prefix of ``Py`` or -``PY``, except those defined in standard header files. - -.. tip:: - - For backward compatibility, :file:`Python.h` includes several standard header files. - C extensions should include the standard headers that they use, - and should not rely on these implicit includes. - If using the limited C API version 3.13 or newer, the implicit includes are: - - * ```` - * ```` (on Windows) - * ```` - * ```` - * ```` - * ```` - * ```` - * ```` (if present) - - If :c:macro:`Py_LIMITED_API` is not defined, or is set to version 3.12 or older, - the headers below are also included: - - * ```` - * ```` (on POSIX) - - If :c:macro:`Py_LIMITED_API` is not defined, or is set to version 3.10 or older, - the headers below are also included: - - * ```` - * ```` - * ```` - * ```` - -The next thing we add to our module file is the C function that will be called -when the Python expression ``spam.system(string)`` is evaluated (we'll see -shortly how it ends up being called):: - - static PyObject * - spam_system(PyObject *self, PyObject *args) - { - const char *command; - int sts; - - if (!PyArg_ParseTuple(args, "s", &command)) - return NULL; - sts = system(command); - return PyLong_FromLong(sts); - } - -There is a straightforward translation from the argument list in Python (for -example, the single expression ``"ls -l"``) to the arguments passed to the C -function. The C function always has two arguments, conventionally named *self* -and *args*. - -The *self* argument points to the module object for module-level functions; -for a method it would point to the object instance. - -The *args* argument will be a pointer to a Python tuple object containing the -arguments. Each item of the tuple corresponds to an argument in the call's -argument list. The arguments are Python objects --- in order to do anything -with them in our C function we have to convert them to C values. The function -:c:func:`PyArg_ParseTuple` in the Python API checks the argument types and -converts them to C values. It uses a template string to determine the required -types of the arguments as well as the types of the C variables into which to -store the converted values. More about this later. - -:c:func:`PyArg_ParseTuple` returns true (nonzero) if all arguments have the right -type and its components have been stored in the variables whose addresses are -passed. It returns false (zero) if an invalid argument list was passed. In the -latter case it also raises an appropriate exception so the calling function can -return ``NULL`` immediately (as we saw in the example). +The :ref:`tutorial ` walked you through +creating a C API extension module, but left many areas unexplained. +This document looks at several concepts that you'll need to learn +in order to write more complex extensions. .. _extending-errors: -Intermezzo: Errors and Exceptions -================================= +Errors and Exceptions +===================== An important convention throughout the Python interpreter is the following: when a function fails, it should set an exception condition and return an error value @@ -321,194 +187,14 @@ call to :c:func:`PyErr_SetString` as shown below:: } -.. _backtoexample: - -Back to the Example -=================== - -Going back to our example function, you should now be able to understand this -statement:: - - if (!PyArg_ParseTuple(args, "s", &command)) - return NULL; - -It returns ``NULL`` (the error indicator for functions returning object pointers) -if an error is detected in the argument list, relying on the exception set by -:c:func:`PyArg_ParseTuple`. Otherwise the string value of the argument has been -copied to the local variable :c:data:`!command`. This is a pointer assignment and -you are not supposed to modify the string to which it points (so in Standard C, -the variable :c:data:`!command` should properly be declared as ``const char -*command``). - -The next statement is a call to the Unix function :c:func:`system`, passing it -the string we just got from :c:func:`PyArg_ParseTuple`:: - - sts = system(command); - -Our :func:`!spam.system` function must return the value of :c:data:`!sts` as a -Python object. This is done using the function :c:func:`PyLong_FromLong`. :: - - return PyLong_FromLong(sts); - -In this case, it will return an integer object. (Yes, even integers are objects -on the heap in Python!) - -If you have a C function that returns no useful argument (a function returning -:c:expr:`void`), the corresponding Python function must return ``None``. You -need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE` -macro):: - - Py_INCREF(Py_None); - return Py_None; - -:c:data:`Py_None` is the C name for the special Python object ``None``. It is a -genuine Python object rather than a ``NULL`` pointer, which means "error" in most -contexts, as we have seen. - - -.. _methodtable: - -The Module's Method Table and Initialization Function -===================================================== - -I promised to show how :c:func:`!spam_system` is called from Python programs. -First, we need to list its name and address in a "method table":: - - static PyMethodDef spam_methods[] = { - ... - {"system", spam_system, METH_VARARGS, - "Execute a shell command."}, - ... - {NULL, NULL, 0, NULL} /* Sentinel */ - }; - -Note the third entry (``METH_VARARGS``). This is a flag telling the interpreter -the calling convention to be used for the C function. It should normally always -be ``METH_VARARGS`` or ``METH_VARARGS | METH_KEYWORDS``; a value of ``0`` means -that an obsolete variant of :c:func:`PyArg_ParseTuple` is used. - -When using only ``METH_VARARGS``, the function should expect the Python-level -parameters to be passed in as a tuple acceptable for parsing via -:c:func:`PyArg_ParseTuple`; more information on this function is provided below. - -The :c:macro:`METH_KEYWORDS` bit may be set in the third field if keyword -arguments should be passed to the function. In this case, the C function should -accept a third ``PyObject *`` parameter which will be a dictionary of keywords. -Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a -function. - -The method table must be referenced in the module definition structure:: - - static struct PyModuleDef spam_module = { - ... - .m_methods = spam_methods, - ... - }; - -This structure, in turn, must be passed to the interpreter in the module's -initialization function. The initialization function must be named -:c:func:`!PyInit_name`, where *name* is the name of the module, and should be the -only non-\ ``static`` item defined in the module file:: - - PyMODINIT_FUNC - PyInit_spam(void) - { - return PyModuleDef_Init(&spam_module); - } - -Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type, -declares any special linkage declarations required by the platform, and for C++ -declares the function as ``extern "C"``. - -:c:func:`!PyInit_spam` is called when each interpreter imports its module -:mod:`!spam` for the first time. (See below for comments about embedding Python.) -A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`, -so that the import machinery can create the module and store it in ``sys.modules``. - -When embedding Python, the :c:func:`!PyInit_spam` function is not called -automatically unless there's an entry in the :c:data:`PyImport_Inittab` table. -To add the module to the initialization table, use :c:func:`PyImport_AppendInittab`, -optionally followed by an import of the module:: - - #define PY_SSIZE_T_CLEAN - #include - - int - main(int argc, char *argv[]) - { - PyStatus status; - PyConfig config; - PyConfig_InitPythonConfig(&config); - - /* Add a built-in module, before Py_Initialize */ - if (PyImport_AppendInittab("spam", PyInit_spam) == -1) { - fprintf(stderr, "Error: could not extend in-built modules table\n"); - exit(1); - } - - /* Pass argv[0] to the Python interpreter */ - status = PyConfig_SetBytesString(&config, &config.program_name, argv[0]); - if (PyStatus_Exception(status)) { - goto exception; - } - - /* Initialize the Python interpreter. Required. - If this step fails, it will be a fatal error. */ - status = Py_InitializeFromConfig(&config); - if (PyStatus_Exception(status)) { - goto exception; - } - PyConfig_Clear(&config); - - /* Optionally import the module; alternatively, - import can be deferred until the embedded script - imports it. */ - PyObject *pmodule = PyImport_ImportModule("spam"); - if (!pmodule) { - PyErr_Print(); - fprintf(stderr, "Error: could not import module 'spam'\n"); - } - - // ... use Python C API here ... - - return 0; - - exception: - PyConfig_Clear(&config); - Py_ExitStatusException(status); - } - -.. note:: - - If you declare a global variable or a local static one, the module may - experience unintended side-effects on re-initialisation, for example when - removing entries from ``sys.modules`` or importing compiled modules into - multiple interpreters within a process - (or following a :c:func:`fork` without an intervening :c:func:`exec`). - If module state is not yet fully :ref:`isolated `, - authors should consider marking the module as having no support for subinterpreters - (via :c:macro:`Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED`). - -A more substantial example module is included in the Python source distribution -as :file:`Modules/xxlimited.c`. This file may be used as a template or simply -read as an example. - - .. _compilation: -Compilation and Linkage -======================= +Embedding an extension +====================== -There are two more things to do before you can use your new extension: compiling -and linking it with the Python system. If you use dynamic loading, the details -may depend on the style of dynamic loading your system uses; see the chapters -about building extension modules (chapter :ref:`building`) and additional -information that pertains only to building on Windows (chapter -:ref:`building-on-windows`) for more information about this. - -If you can't use dynamic loading, or if you want to make your module a permanent +If you want to make your module a permanent part of the Python interpreter, you will have to change the configuration setup -and rebuild the interpreter. Luckily, this is very simple on Unix: just place +and rebuild the interpreter. On Unix, place your file (:file:`spammodule.c` for example) in the :file:`Modules/` directory of an unpacked source distribution, add a line to the file :file:`Modules/Setup.local` describing your file: @@ -536,7 +222,7 @@ on the line in the configuration file as well, for instance: Calling Python Functions from C =============================== -So far we have concentrated on making C functions callable from Python. The +The tutorial concentrated on making C functions callable from Python. The reverse is also useful: calling Python functions from C. This is especially the case for libraries that support so-called "callback" functions. If a C interface makes use of callbacks, the equivalent Python often needs to provide a @@ -581,7 +267,7 @@ be part of a module definition:: } This function must be registered with the interpreter using the -:c:macro:`METH_VARARGS` flag; this is described in section :ref:`methodtable`. The +:c:macro:`METH_VARARGS` flag in :c:type:`PyMethodDef.ml_flags`. The :c:func:`PyArg_ParseTuple` function and its arguments are documented in section :ref:`parsetuple`. @@ -676,14 +362,21 @@ the above example, we use :c:func:`Py_BuildValue` to construct the dictionary. : Py_DECREF(result); +.. index:: single: PyArg_ParseTuple (C function) + .. _parsetuple: Extracting Parameters in Extension Functions ============================================ -.. index:: single: PyArg_ParseTuple (C function) +The :ref:`tutorial ` uses a ":c:data:`METH_O`" +function, which is limited to a single Python argument. +If you want more, you can use :c:data:`METH_VARARGS` instead. +With this flag, the C function will receive a :py:class:`tuple` of arguments +instead of a single object. -The :c:func:`PyArg_ParseTuple` function is declared as follows:: +For unpacking the tuple, CPython provides the :c:func:`PyArg_ParseTuple` +function, declared as follows:: int PyArg_ParseTuple(PyObject *arg, const char *format, ...); @@ -693,6 +386,19 @@ whose syntax is explained in :ref:`arg-parsing` in the Python/C API Reference Manual. The remaining arguments must be addresses of variables whose type is determined by the format string. +For example, to receive a single Python :py:class:`str` object and turn it +into a C buffer, you would use ``"s"`` as the format string:: + + const char *command; + if (!PyArg_ParseTuple(args, "s", &command)) { + return NULL; + } + +If an error is detected in the argument list, :c:func:`!PyArg_ParseTuple` +returns ``NULL`` (the error indicator for functions returning object pointers); +your function may return ``NULL``, relying on the exception set by +:c:func:`PyArg_ParseTuple`. + Note that while :c:func:`PyArg_ParseTuple` checks that the Python arguments have the required types, it cannot check the validity of the addresses of C variables passed to the call: if you make mistakes there, your code will probably crash or @@ -703,7 +409,6 @@ Note that any Python object references which are provided to the caller are Some example calls:: - #define PY_SSIZE_T_CLEAN #include :: @@ -773,6 +478,17 @@ Some example calls:: Keyword Parameters for Extension Functions ========================================== +If you also want your function to accept +:term:`keyword arguments `, use the :c:data:`METH_KEYWORDS` +flag in combination with :c:data:`METH_VARARGS`. +(:c:data:`!METH_KEYWORDS` can also be used with other flags; see its +documentation for the allowed combinations.) + +In this case, the C function should accept a third ``PyObject *`` parameter +which will be a dictionary of keywords. +Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a +function. + .. index:: single: PyArg_ParseTupleAndKeywords (C function) The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows:: @@ -833,19 +549,6 @@ Philbrick (philbrick@hks.com):: {NULL, NULL, 0, NULL} /* sentinel */ }; - static struct PyModuleDef keywdarg_module = { - .m_base = PyModuleDef_HEAD_INIT, - .m_name = "keywdarg", - .m_size = 0, - .m_methods = keywdarg_methods, - }; - - PyMODINIT_FUNC - PyInit_keywdarg(void) - { - return PyModuleDef_Init(&keywdarg_module); - } - .. _buildvalue: @@ -986,11 +689,11 @@ needed. Ownership of a reference can be transferred. There are three ways to dispose of an owned reference: pass it on, store it, or call :c:func:`Py_DECREF`. Forgetting to dispose of an owned reference creates a memory leak. -It is also possible to :dfn:`borrow` [#]_ a reference to an object. The +It is also possible to :dfn:`borrow` [#borrow]_ a reference to an object. The borrower of a reference should not call :c:func:`Py_DECREF`. The borrower must not hold on to the object longer than the owner from which it was borrowed. Using a borrowed reference after the owner has disposed of it risks using freed -memory and should be avoided completely [#]_. +memory and should be avoided completely [#dont-check-refcount]_. The advantage of borrowing over owning a reference is that you don't need to take care of disposing of the reference on all possible paths through the code @@ -1169,7 +872,7 @@ checking. The C function calling mechanism guarantees that the argument list passed to C functions (``args`` in the examples) is never ``NULL`` --- in fact it guarantees -that it is always a tuple [#]_. +that it is always a tuple [#old-calling-convention]_. It is a severe error to ever let a ``NULL`` pointer "escape" to the Python user. @@ -1226,8 +929,8 @@ the module whose functions one wishes to call might not have been loaded yet! Portability therefore requires not to make any assumptions about symbol visibility. This means that all symbols in extension modules should be declared ``static``, except for the module's initialization function, in order to -avoid name clashes with other extension modules (as discussed in section -:ref:`methodtable`). And it means that symbols that *should* be accessible from +avoid name clashes with other extension modules. And it means that symbols +that *should* be accessible from other extension modules must be exported in a different way. Python provides a special mechanism to pass C-level information (pointers) from @@ -1269,8 +972,9 @@ file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. -The exporting module is a modification of the :mod:`!spam` module from section -:ref:`extending-simpleexample`. The function :func:`!spam.system` does not call +The exporting module is a modification of the :mod:`!spam` module from the +:ref:`tutorial `. +The function :func:`!spam.system` does not call the C library function :c:func:`system` directly, but a function :c:func:`!PySpam_System`, which would of course do something more complicated in reality (such as adding "spam" to every command). This function @@ -1412,15 +1116,14 @@ code distribution). .. rubric:: Footnotes -.. [#] An interface for this function already exists in the standard module :mod:`os` - --- it was chosen as a simple and straightforward example. - -.. [#] The metaphor of "borrowing" a reference is not completely correct: the owner - still has a copy of the reference. +.. [#borrow] The metaphor of "borrowing" a reference is not completely correct: + the owner still has a copy of the reference. -.. [#] Checking that the reference count is at least 1 **does not work** --- the +.. [#dont-check-refcount] Checking that the reference count is at least 1 + **does not work** --- the reference count itself could be in freed memory and may thus be reused for another object! -.. [#] These guarantees don't hold when you use the "old" style calling convention --- +.. [#old-calling-convention] These guarantees don't hold when you use the + "old" style calling convention --- this is still found in much existing code. diff --git a/Doc/extending/first-extension-module.rst b/Doc/extending/first-extension-module.rst new file mode 100644 index 00000000000000..5bde785c49e81e --- /dev/null +++ b/Doc/extending/first-extension-module.rst @@ -0,0 +1,667 @@ +.. highlight:: c + + +.. _extending-simpleexample: +.. _first-extension-module: + +********************************* +Your first C API extension module +********************************* + +This tutorial will take you through creating a simple +Python extension module written in C or C++. + +We will use the low-level Python C API directly. +For easier ways to create extension modules, see +the :ref:`recommended third party tools `. + +The tutorial assumes basic knowledge about Python: you should be able to +define functions in Python code before starting to write them in C. +See :ref:`tutorial-index` for an introduction to Python itself. + +The tutorial should be approachable for anyone who can write a basic C library. +While we will mention several concepts that a C beginner would not be expected +to know, like ``static`` functions or linkage declarations, understanding these +is not necessary for success. + +We will focus on giving you a "feel" of what Python's C API is like. +It will not teach you important concepts, like error handling +and reference counting, which are covered in later chapters. + +We will assume that you use a Unix-like system (including macOS and +Linux), or Windows. +On other systems, you might need to adjust some details -- for example, +a system command name. + +You need to have a suitable C compiler and Python development headers installed. +On Linux, headers are often in a package like ``python3-dev`` +or ``python3-devel``. + +You need to be able to install Python packages. +This tutorial uses `pip `__ (``pip install``), but you +can substitute any tool that can build and install ``pyproject.toml``-based +projects, like `uv `_ (``uv pip install``). +Preferably, have a :ref:`virtual environment ` activated. + + +.. note:: + + This tutorial uses APIs that were added in CPython 3.15. + To create an extension that's compatible with earlier versions of CPython, + please follow an earlier version of this documentation. + + This tutorial uses C syntax added in C11 and C++20. + If your extension needs to be compatible with earlier standards, + please follow tutorials in documentation for Python 3.14 or below. + + +What we'll do +============= + +Let's create an extension module called ``spam`` [#why-spam]_, +which will include a Python interface to the C +standard library function :c:func:`system`. +This function is defined in ``stdlib.h``. +It takes a C string as argument, runs the argument as a system +command, and returns a result value as an integer. +A manual page for :c:func:`system` might summarize it this way:: + + #include + int system(const char *command); + +Note that like many functions in the C standard library, +this function is already exposed in Python. +In production, use :py:func:`os.system` or :py:func:`subprocess.run` +rather than the module you'll write here. + +We want this function to be callable from Python as follows: + +.. code-block:: pycon + + >>> import spam + >>> status = spam.system("whoami") + User Name + >>> status + 0 + +.. note:: + + The system command ``whoami`` prints out your username. + It's useful in tutorials like this one because it has the same name on + both Unix and Windows. + + +Start with the headers +====================== + +Begin by creating a directory for this tutorial, and switching to it +on the command line. +Then, create a file named :file:`spammodule.c` in your directory. +[#why-spammodule]_ + +In this file, we'll include two headers: :file:`Python.h` to pull in +all declarations of the Python C API, and :file:`stdlib.h` for the +:c:func:`system` function. [#stdlib-h]_ + +Add the following lines to :file:`spammodule.c`: + +.. literalinclude:: ../includes/capi-extension/spammodule-01.c + :start-at: + :end-at: + +Be sure to put :file:`stdlib.h`, and any other standard library includes, +*after* :file:`Python.h`. +On some systems, Python may define some pre-processor definitions +that affect the standard headers. + + +Running your build tool +======================= + +With only the includes in place, your extension won't do anything. +Still, it's a good time to compile it and try to import it. +This will ensure that your build tool works, so that you can make +and test incremental changes as you follow the rest of the text. + +CPython itself does not come with a tool to build extension modules; +it is recommended to use a third-party project for this. +In this tutorial, we'll use `meson-python`_. +(If you want to use another one, see :ref:`first-extension-other-tools`.) + +.. at the time of writing, meson-python has the least overhead for a + simple extension using PyModExport. + Change this if another tool makes things easier. + +``meson-python`` requires defining a "project" using two extra files. + +First, add ``pyproject.toml`` with these contents: + +.. code-block:: toml + + [build-system] + build-backend = 'mesonpy' + requires = ['meson-python'] + + [project] + # Placeholder project information + # (change this before distributing the module) + name = 'sampleproject' + version = '0' + +Then, create ``meson.build`` containing the following: + +.. code-block:: meson + + project('sampleproject', 'c') + + py = import('python').find_installation(pure: false) + + py.extension_module( + 'spam', # name of the importable Python module + 'spammodule.c', # the C source file + install: true, + ) + +.. note:: + + See `meson-python documentation `_ for details on + configuration. + +Now, build install the *project in the current directory* (``.``) via ``pip``: + +.. code-block:: sh + + python -m pip install . + +.. tip:: + + If you don't have ``pip`` installed, run ``python -m ensurepip``, + preferably in a :ref:`virtual environment `. + (Or, if you prefer another tool that can build and install + ``pyproject.toml``-based projects, use that.) + +.. _meson-python: https://mesonbuild.com/meson-python/ +.. _virtual environment: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#create-and-use-virtual-environments + +Note that you will need to run this command again every time you change your +extension. +Unlike Python, C has an explicit compilation step. + +When your extension is compiled and installed, start Python and try to +import it. +This should fail with the following exception: + +.. code-block:: pycon + + >>> import spam + Traceback (most recent call last): + ... + ImportError: dynamic module does not define module export function (PyModExport_spam or PyInit_spam) + + +Module export hook +================== + +The exception you got when you tried to import the module told you that Python +is looking for a "module export function", also known as a +:ref:`module export hook `. +Let's define one. + +First, add a prototype below the ``#include`` lines: + +.. literalinclude:: ../includes/capi-extension/spammodule-01.c + :start-after: /// Export hook prototype + :end-before: /// + +.. tip:: + The prototype is not strictly necessary, but some modern compilers emit + warnings without it. + It's generally better to add the prototype than to disable the warning. + +The :c:macro:`PyMODEXPORT_FUNC` macro declares the function's +return type, and adds any special linkage declarations needed +to make the function visible and usable when CPython loads it. + +After the prototype, add the function itself. +For now, make it return ``NULL``: + +.. code-block:: c + + PyMODEXPORT_FUNC + PyModExport_spam(void) + { + return NULL; + } + +Compile and load the module again. +You should get a different error this time. + +.. code-block:: pycon + + >>> import spam + Traceback (most recent call last): + ... + SystemError: module export hook for module 'spam' failed without setting an exception + +Simply returning ``NULL`` is *not* correct behavior for an export hook, +and CPython complains about it. +That's good -- it means that CPython found the function! +Let's now make it do something useful. + + +The slot table +============== + +Rather than ``NULL``, the export hook should return the information needed to +create a module. +Let's start with the basics: the name and docstring. + +The information should be defined in a ``static`` array of +:c:type:`PyModuleDef_Slot` entries, which are essentially key-value pairs. +Define this array just before your export hook: + +.. code-block:: c + + static PyModuleDef_Slot spam_slots[] = { + {Py_mod_name, "spam"}, + {Py_mod_doc, "A wonderful module with an example function"}, + {0, NULL} + }; + +For both :c:data:`Py_mod_name` and :c:data:`Py_mod_doc`, the values are C +strings -- that is, NUL-terminated, UTF-8 encoded byte arrays. + +Note the zero-filled sentinel entry at the end. +If you forget it, you'll trigger undefined behavior. + +The array is defined as ``static`` -- that is, not visible outside this ``.c`` file. +This will be a common theme. +CPython only needs to access the export hook; all global variables +and all other functions should generally be ``static``, so that they don't +clash with other extensions. + +Return this array from your export hook instead of ``NULL``: + +.. code-block:: c + :emphasize-lines: 4 + + PyMODEXPORT_FUNC + PyModExport_spam(void) + { + return spam_slots; + } + +Now, recompile and try it out: + +.. code-block:: pycon + + >>> import spam + >>> print(spam) + + +You have an extension module! +Try ``help(spam)`` to see the docstring. + +The next step will be adding a function. + + +.. _backtoexample: + +Exposing a function +=================== + +To expose the :c:func:`system` C function directly to Python, +we'll need to write a layer of glue code to convert arguments from Python +objects to C values, and the C return value back to Python. + +One of the simplest ways to write glue code is a ":c:data:`METH_O`" function, +which takes two Python objects and returns one. +All Python objects -- regardless of the Python type -- are represented in C +as pointers to the :c:type:`PyObject` structure. + +Add such a function above the slots array:: + + static PyObject * + spam_system(PyObject *self, PyObject *arg) + { + Py_RETURN_NONE; + } + +For now, we ignore the arguments, and use the :c:macro:`Py_RETURN_NONE` +macro, which expands to a ``return`` statement that properly returns +a Python :py:data:`None` object. + +Recompile your extension to make sure you don't have syntax errors. +We haven't yet added ``spam_system`` to the module, so you might get a +warning that ``spam_system`` is unused. + +.. _methodtable: + +Method definitions +------------------ + +To expose the C function to Python, you will need to provide several pieces of +information in a structure called +:c:type:`PyMethodDef` [#why-pymethoddef]_: + +* ``ml_name``: the name of the Python function; +* ``ml_doc``: a docstring; +* ``ml_meth``: the C function to be called; and +* ``ml_flags``: a set of flags describing details like how Python arguments are + passed to the C function. + We'll use :c:data:`METH_O` here -- the flag that matches our + ``spam_system`` function's signature. + +Because modules typically create several functions, these definitions +need to be collected in an array, with a zero-filled sentinel at the end. +Add this array just below the ``spam_system`` function: + +.. literalinclude:: ../includes/capi-extension/spammodule-01.c + :start-after: /// Module method table + :end-before: /// + +As with module slots, a zero-filled sentinel marks the end of the array. + +Next, we'll add the method to the module. +Add a :c:data:`Py_mod_methods` slot to your :c:type:`PyMethodDef` array: + +.. literalinclude:: ../includes/capi-extension/spammodule-01.c + :start-after: /// Module slot table + :end-before: /// + :emphasize-lines: 5 + +Recompile your extension again, and test it. +Be sure to restart the Python interpreter, so that ``import spam`` picks +up the new version of the module. + +You should now be able to call the function: + +.. code-block:: pycon + + >>> import spam + >>> print(spam.system) + + >>> print(spam.system('whoami')) + None + +Note that our ``spam.system`` does not yet run the ``whoami`` command; +it only returns ``None``. + +Check that the function accepts exactly one argument, as specified by +the :c:data:`METH_O` flag: + +.. code-block:: pycon + + >>> print(spam.system('too', 'many', 'arguments')) + Traceback (most recent call last): + ... + TypeError: spam.system() takes exactly one argument (3 given) + + +Returning an integer +==================== + +Now, let's take a look at the return value. +Instead of ``None``, we'll want ``spam.system`` to return a number -- that is, +a Python :py:type:`int` object. +Eventually this will be the exit code of a system command, +but let's start with a fixed value, say, ``3``. + +The Python C API provides a function to create a Python :py:type:`int` object +from a C ``int`` value: :c:func:`PyLong_FromLong`. [#why-pylongfromlong]_ + +To call it, replace the ``Py_RETURN_NONE`` with the following 3 lines: + +.. this could be a one-liner, but we want to show the data types here + +.. code-block:: c + :emphasize-lines: 4-6 + + static PyObject * + spam_system(PyObject *self, PyObject *arg) + { + int status = 3; + PyObject *result = PyLong_FromLong(status); + return result; + } + + +Recompile, restart the Python interpreter again, +and check that the function now returns 3: + +.. code-block:: pycon + + >>> import spam + >>> spam.system('whoami') + 3 + + +Accepting a string +================== + +Finally, let's handle the function argument. + +Our C function, :c:func:`!spam_system`, takes two arguments. +The first one, ``PyObject *self``, will be set to the ``spam`` module +object. +This isn't useful in our case, so we'll ignore it. + +The other one, ``PyObject *arg``, will be set to the object that the user +passed from Python. +We expect that it should be a Python string. +In order to use the information in it, we will need +to convert it to a C value -- in this case, a C string (``const char *``). + +There's a slight type mismatch here: Python's :py:class:`str` objects store +Unicode text, but C strings are arrays of bytes. +So, we'll need to *encode* the data, and we'll use the UTF-8 encoding for it. +(UTF-8 might not always be correct for system commands, but it's what +:py:meth:`str.encode` uses by default, +and the C API has special support for it.) + +The function to encode a Python string into a UTF-8 buffer is named +:c:func:`PyUnicode_AsUTF8` [#why-pyunicodeasutf8]_. +Call it like this: + +.. code-block:: c + :emphasize-lines: 4 + + static PyObject * + spam_system(PyObject *self, PyObject *arg) + { + const char *command = PyUnicode_AsUTF8(arg); + int status = 3; + PyObject *result = PyLong_FromLong(status); + return result; + } + +If :c:func:`PyUnicode_AsUTF8` is successful, *command* will point to the +resulting array of bytes. +This buffer is managed by the *arg* object, which means we don't need to free +it, but we must follow some rules: + +* We should only use the buffer inside the ``spam_system`` function. + When ``spam_system`` returns, *arg* and the buffer it manages might be + garbage-collected. +* We must not modify it. This is why we use ``const``. + +If :c:func:`PyUnicode_AsUTF8` was *not* successful, it returns a ``NULL`` +pointer. +When calling *any* Python C API, we always need to handle such error cases. +The way to do this in general is left for later chapters of this documentation. +For now, be assured that we are already handling errors from +:c:func:`PyLong_FromLong` correctly. + +For the :c:func:`PyUnicode_AsUTF8` call, the correct way to handle errors is +returning ``NULL`` from ``spam_system``. +Add an ``if`` block for this: + + +.. code-block:: c + :emphasize-lines: 5-7 + + static PyObject * + spam_system(PyObject *self, PyObject *arg) + { + const char *command = PyUnicode_AsUTF8(arg); + if (command == NULL) { + return NULL; + } + int status = 3; + PyObject *result = PyLong_FromLong(status); + return result; + } + +That's it for the setup. +Now, all that is left is calling the C library function :c:func:`system` with +the ``char *`` buffer, and using its result instead of the ``3``: + +.. code-block:: c + :emphasize-lines: 8 + + static PyObject * + spam_system(PyObject *self, PyObject *arg) + { + const char *command = PyUnicode_AsUTF8(arg); + if (command == NULL) { + return NULL; + } + int status = system(command); + PyObject *result = PyLong_FromLong(status); + return result; + } + +Compile your module, restart Python, and test. +This time, you should see your username -- the output of the ``whoami`` +system command: + +.. code-block:: pycon + + >>> import spam + >>> result = spam.system('whoami') + User Name + >>> result + 0 + +You might also want to test error cases: + +.. code-block:: pycon + + >>> import spam + >>> result = spam.system('nonexistent-command') + sh: line 1: nonexistent-command: command not found + >>> result + 32512 + + >>> spam.system(3) + Traceback (most recent call last): + ... + TypeError: bad argument type for built-in operation + + +The result +========== + + +Congratulations! +You have written a complete Python C API extension module, +and completed this tutorial! + +Here is the entire source file, for your convenience: + +.. _extending-spammodule-source: + +.. literalinclude:: ../includes/capi-extension/spammodule-01.c + :start-at: /// + + +.. _first-extension-other-tools: + +Appendix: Other build tools +=========================== + +You should be able to follow this tutorial -- except the +*Running your build tool* section itself -- with a build tool other +than ``meson-python``. + +The Python Packaging User Guide has a `list of recommended tools `_; +be sure to choose one for the C language. + + +Workaround for missing PyInit function +-------------------------------------- + +If your build tool output complains about missing ``PyInit_spam``, +add the following function to your module for now: + +.. code-block:: c + + // A workaround + void *PyInit_spam(void) { return NULL; } + +This is a shim for an old-style :ref:`initialization function `, +which was required in extension modules for CPython 3.14 and below. +Current CPython does not need it, but some build tools may still assume that +all extension modules need to define it. + +If you use this workaround, you will get the exception +``SystemError: initialization of spam failed without raising an exception`` +instead of +``ImportError: dynamic module does not define module export function``. + + +Compiling directly +------------------ + +Using a third-party build tool is heavily recommended, +as it will take care of various details of your platform and Python +installation, of naming the resulting extension, and, later, of distributing +your work. + +If you are building an extension for as *specific* system, or for yourself +only, you might instead want to run your compiler directly. +The way to do this is system-specific; be prepared for issues you will need +to solve yourself. + +Linux +^^^^^ + +On Linux, the Python development package may include a ``python3-config`` +command that prints out the required compiler flags. +If you use it, check that it corresponds to the CPython interpreter you'll use +to load the module. +Then, start with the following command: + +.. code-block:: sh + + gcc --shared $(python3-config --cflags --ldflags) spammodule.c -o spam.so + +This should generate a ``spam.so`` file that you need to put in a directory +on :py:attr:`sys.path`. + + +.. rubric:: Footnotes + +.. [#why-spam] ``spam`` is the favorite food of Monty Python fans... +.. [#why-spammodule] The source file name is entirely up to you, + though some tools can be picky about the ``.c`` extension. + This tutorial uses the traditional ``*module.c`` suffix. + Some people would just use :file:`spam.c` to implement a module + named ``spam``, + projects where Python isn't the primary language might use ``py_spam.c``, + and so on. +.. [#stdlib-h] Including :file:`stdlib.h` is technically not necessary, + since :file:`Python.h` includes it and + :ref:`several other standard headers ` for its own use + or for backwards compatibility. + However, it is good practice to explicitly include what you need. +.. [#why-pymethoddef] The :c:type:`!PyMethodDef` structure is also used + to create methods of classes, so there's no separate + ":c:type:`!PyFunctionDef`". +.. [#why-pylongfromlong] The name :c:func:`PyLong_FromLong` + might not seem obvious. + ``PyLong`` refers to a the Python :py:class:`int`, which was originally + called ``long``; the ``FromLong`` refers to the C ``long`` (or ``long int``) + type. +.. [#why-pyunicodeasutf8] Here, ``PyUnicode`` refers to the original name of + the Python :py:class:`str` class: ``unicode``. diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst index 4cc2c96d8d5b47..c0c494c3059d99 100644 --- a/Doc/extending/index.rst +++ b/Doc/extending/index.rst @@ -5,15 +5,17 @@ ################################################## This document describes how to write modules in C or C++ to extend the Python -interpreter with new modules. Those modules can not only define new functions -but also new object types and their methods. The document also describes how +interpreter with new modules. Those modules can do what Python code does -- +define functions, object types and methods -- but also interact with native +libraries or achieve better performance by avoiding the overhead of an +interpreter. The document also describes how to embed the Python interpreter in another application, for use as an extension language. Finally, it shows how to compile and link extension modules so that they can be loaded dynamically (at run time) into the interpreter, if the underlying operating system supports this feature. -This document assumes basic knowledge about Python. For an informal -introduction to the language, see :ref:`tutorial-index`. :ref:`reference-index` +This document assumes basic knowledge about C and Python. For an informal +introduction to Python, see :ref:`tutorial-index`. :ref:`reference-index` gives a more formal definition of the language. :ref:`library-index` documents the existing object types, functions and modules (both built-in and written in Python) that give the language its wide application range. @@ -21,37 +23,75 @@ Python) that give the language its wide application range. For a detailed description of the whole Python/C API, see the separate :ref:`c-api-index`. +To support extensions, Python's C API (Application Programmers Interface) +defines a set of functions, macros and variables that provide access to most +aspects of the Python run-time system. The Python API is incorporated in a C +source file by including the header ``"Python.h"``. + +.. note:: + + The C extension interface is specific to CPython, and extension modules do + not work on other Python implementations. In many cases, it is possible to + avoid writing C extensions and preserve portability to other implementations. + For example, if your use case is calling C library functions or system calls, + you should consider using the :mod:`ctypes` module or the `cffi + `_ library rather than writing + custom C code. + These modules let you write Python code to interface with C code and are more + portable between implementations of Python than writing and compiling a C + extension module. + + +.. toctree:: + :hidden: + + first-extension-module.rst + extending.rst + newtypes_tutorial.rst + newtypes.rst + building.rst + windows.rst + embedding.rst + Recommended third party tools ============================= -This guide only covers the basic tools for creating extensions provided +This document only covers the basic tools for creating extensions provided as part of this version of CPython. Some :ref:`third party tools ` offer both simpler and more sophisticated approaches to creating C and C++ extensions for Python. +While this document is aimed at extension authors, it should also be helpful to +the authors of such tools. +For example, the tutorial module can serve as a simple test case for a build +tool or sample expected output of a code generator. + + +C API Tutorial +============== + +This tutorial describes how to write a simple module in C or C++, +using the Python C API -- that is, using the basic tools provided +as part of this version of CPython. -Creating extensions without third party tools -============================================= + +#. :ref:`first-extension-module` + + +Guides for intermediate topics +============================== This section of the guide covers creating C and C++ extensions without assistance from third party tools. It is intended primarily for creators of those tools, rather than being a recommended way to create your own C extensions. -.. seealso:: - - :pep:`489` -- Multi-phase extension module initialization - -.. toctree:: - :maxdepth: 2 - :numbered: - - extending.rst - newtypes_tutorial.rst - newtypes.rst - building.rst - windows.rst +* :ref:`extending-intro` +* :ref:`defining-new-types` +* :ref:`new-types-topics` +* :ref:`building` +* :ref:`building-on-windows` Embedding the CPython runtime in a larger application ===================================================== @@ -61,8 +101,4 @@ interpreter as the main application, it is desirable to instead embed the CPython runtime inside a larger application. This section covers some of the details involved in doing that successfully. -.. toctree:: - :maxdepth: 2 - :numbered: - - embedding.rst +* :ref:`embedding` diff --git a/Doc/includes/capi-extension/spammodule-01.c b/Doc/includes/capi-extension/spammodule-01.c new file mode 100644 index 00000000000000..86c9840359d9c7 --- /dev/null +++ b/Doc/includes/capi-extension/spammodule-01.c @@ -0,0 +1,55 @@ +/* This file needs to be kept in sync with the tutorial + * at Doc/extending/first-extension-module.rst + */ + +/// Includes + +#include +#include // for system() + +/// Implementation of spam.system + +static PyObject * +spam_system(PyObject *self, PyObject *arg) +{ + const char *command = PyUnicode_AsUTF8(arg); + if (command == NULL) { + return NULL; + } + int status = system(command); + PyObject *result = PyLong_FromLong(status); + return result; +} + +/// Module method table + +static PyMethodDef spam_methods[] = { + { + .ml_name="system", + .ml_meth=spam_system, + .ml_flags=METH_O, + .ml_doc="Execute a shell command.", + }, + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +/// Module slot table + +static PyModuleDef_Slot spam_slots[] = { + {Py_mod_name, "spam"}, + {Py_mod_doc, "A wonderful module with an example function"}, + {Py_mod_methods, spam_methods}, + {0, NULL} +}; + +/// Export hook prototype + +PyMODEXPORT_FUNC PyModExport_spam(void); + +/// Module export hook + +PyMODEXPORT_FUNC +PyModExport_spam(void) +{ + return spam_slots; +} From 786f464c740a2f2bf60871feaf73df87b315877b Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 20 Dec 2025 01:43:36 +0800 Subject: [PATCH 022/105] gh-142961: Fix constant folding len(tuple) in JIT (GH-142963) --- Include/internal/pycore_uop_ids.h | 1543 +++++++++-------- Include/internal/pycore_uop_metadata.h | 21 + Lib/test/test_capi/test_opt.py | 12 + ...-12-19-00-59-29.gh-issue-142961.q8WRSq.rst | 1 + Python/bytecodes.c | 7 + Python/executor_cases.c.h | 100 ++ Python/optimizer_bytecodes.c | 6 +- Python/optimizer_cases.c.h | 18 +- 8 files changed, 931 insertions(+), 777 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-19-00-59-29.gh-issue-142961.q8WRSq.rst diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index e9851b767bc835..6130e5cad21bf4 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -314,788 +314,793 @@ extern "C" { #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _SPILL_OR_RELOAD 524 -#define _START_EXECUTOR 525 -#define _STORE_ATTR 526 -#define _STORE_ATTR_INSTANCE_VALUE 527 -#define _STORE_ATTR_SLOT 528 -#define _STORE_ATTR_WITH_HINT 529 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 524 +#define _SPILL_OR_RELOAD 525 +#define _START_EXECUTOR 526 +#define _STORE_ATTR 527 +#define _STORE_ATTR_INSTANCE_VALUE 528 +#define _STORE_ATTR_SLOT 529 +#define _STORE_ATTR_WITH_HINT 530 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 530 -#define _STORE_FAST_0 531 -#define _STORE_FAST_1 532 -#define _STORE_FAST_2 533 -#define _STORE_FAST_3 534 -#define _STORE_FAST_4 535 -#define _STORE_FAST_5 536 -#define _STORE_FAST_6 537 -#define _STORE_FAST_7 538 +#define _STORE_FAST 531 +#define _STORE_FAST_0 532 +#define _STORE_FAST_1 533 +#define _STORE_FAST_2 534 +#define _STORE_FAST_3 535 +#define _STORE_FAST_4 536 +#define _STORE_FAST_5 537 +#define _STORE_FAST_6 538 +#define _STORE_FAST_7 539 #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 539 -#define _STORE_SUBSCR 540 -#define _STORE_SUBSCR_DICT 541 -#define _STORE_SUBSCR_LIST_INT 542 -#define _SWAP 543 -#define _SWAP_2 544 -#define _SWAP_3 545 -#define _TIER2_RESUME_CHECK 546 -#define _TO_BOOL 547 +#define _STORE_SLICE 540 +#define _STORE_SUBSCR 541 +#define _STORE_SUBSCR_DICT 542 +#define _STORE_SUBSCR_LIST_INT 543 +#define _SWAP 544 +#define _SWAP_2 545 +#define _SWAP_3 546 +#define _TIER2_RESUME_CHECK 547 +#define _TO_BOOL 548 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 548 +#define _TO_BOOL_LIST 549 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 549 +#define _TO_BOOL_STR 550 #define _TRACE_RECORD TRACE_RECORD #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 550 -#define _UNPACK_SEQUENCE_LIST 551 -#define _UNPACK_SEQUENCE_TUPLE 552 -#define _UNPACK_SEQUENCE_TWO_TUPLE 553 +#define _UNPACK_SEQUENCE 551 +#define _UNPACK_SEQUENCE_LIST 552 +#define _UNPACK_SEQUENCE_TUPLE 553 +#define _UNPACK_SEQUENCE_TWO_TUPLE 554 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 553 -#define _BINARY_OP_r21 554 -#define _BINARY_OP_ADD_FLOAT_r03 555 -#define _BINARY_OP_ADD_FLOAT_r13 556 -#define _BINARY_OP_ADD_FLOAT_r23 557 -#define _BINARY_OP_ADD_INT_r03 558 -#define _BINARY_OP_ADD_INT_r13 559 -#define _BINARY_OP_ADD_INT_r23 560 -#define _BINARY_OP_ADD_UNICODE_r03 561 -#define _BINARY_OP_ADD_UNICODE_r13 562 -#define _BINARY_OP_ADD_UNICODE_r23 563 -#define _BINARY_OP_EXTEND_r21 564 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r20 565 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 566 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 567 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 568 -#define _BINARY_OP_MULTIPLY_INT_r03 569 -#define _BINARY_OP_MULTIPLY_INT_r13 570 -#define _BINARY_OP_MULTIPLY_INT_r23 571 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 572 -#define _BINARY_OP_SUBSCR_DICT_r21 573 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 574 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 575 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 576 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 577 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 578 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 579 -#define _BINARY_OP_SUBSCR_STR_INT_r23 580 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r21 581 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 582 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 583 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 584 -#define _BINARY_OP_SUBTRACT_INT_r03 585 -#define _BINARY_OP_SUBTRACT_INT_r13 586 -#define _BINARY_OP_SUBTRACT_INT_r23 587 -#define _BINARY_SLICE_r31 588 -#define _BUILD_INTERPOLATION_r01 589 -#define _BUILD_LIST_r01 590 -#define _BUILD_MAP_r01 591 -#define _BUILD_SET_r01 592 -#define _BUILD_SLICE_r01 593 -#define _BUILD_STRING_r01 594 -#define _BUILD_TEMPLATE_r21 595 -#define _BUILD_TUPLE_r01 596 -#define _CALL_BUILTIN_CLASS_r01 597 -#define _CALL_BUILTIN_FAST_r01 598 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 599 -#define _CALL_BUILTIN_O_r03 600 -#define _CALL_INTRINSIC_1_r11 601 -#define _CALL_INTRINSIC_2_r21 602 -#define _CALL_ISINSTANCE_r31 603 -#define _CALL_KW_NON_PY_r11 604 -#define _CALL_LEN_r33 605 -#define _CALL_LIST_APPEND_r02 606 -#define _CALL_LIST_APPEND_r12 607 -#define _CALL_LIST_APPEND_r22 608 -#define _CALL_LIST_APPEND_r32 609 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 610 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 611 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 612 -#define _CALL_METHOD_DESCRIPTOR_O_r01 613 -#define _CALL_NON_PY_GENERAL_r01 614 -#define _CALL_STR_1_r32 615 -#define _CALL_TUPLE_1_r32 616 -#define _CALL_TYPE_1_r31 617 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 618 -#define _CHECK_ATTR_CLASS_r01 619 -#define _CHECK_ATTR_CLASS_r11 620 -#define _CHECK_ATTR_CLASS_r22 621 -#define _CHECK_ATTR_CLASS_r33 622 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 623 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 624 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 625 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 626 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 627 -#define _CHECK_EG_MATCH_r22 628 -#define _CHECK_EXC_MATCH_r22 629 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 630 -#define _CHECK_FUNCTION_VERSION_r00 631 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 632 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 633 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 634 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 635 -#define _CHECK_FUNCTION_VERSION_KW_r11 636 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 637 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 638 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 639 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 640 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 641 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 642 -#define _CHECK_METHOD_VERSION_r00 643 -#define _CHECK_METHOD_VERSION_KW_r11 644 -#define _CHECK_PEP_523_r00 645 -#define _CHECK_PEP_523_r11 646 -#define _CHECK_PEP_523_r22 647 -#define _CHECK_PEP_523_r33 648 -#define _CHECK_PERIODIC_r00 649 -#define _CHECK_PERIODIC_AT_END_r00 650 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 651 -#define _CHECK_RECURSION_REMAINING_r00 652 -#define _CHECK_RECURSION_REMAINING_r11 653 -#define _CHECK_RECURSION_REMAINING_r22 654 -#define _CHECK_RECURSION_REMAINING_r33 655 -#define _CHECK_STACK_SPACE_r00 656 -#define _CHECK_STACK_SPACE_OPERAND_r00 657 -#define _CHECK_STACK_SPACE_OPERAND_r11 658 -#define _CHECK_STACK_SPACE_OPERAND_r22 659 -#define _CHECK_STACK_SPACE_OPERAND_r33 660 -#define _CHECK_VALIDITY_r00 661 -#define _CHECK_VALIDITY_r11 662 -#define _CHECK_VALIDITY_r22 663 -#define _CHECK_VALIDITY_r33 664 -#define _COLD_DYNAMIC_EXIT_r00 665 -#define _COLD_EXIT_r00 666 -#define _COMPARE_OP_r21 667 -#define _COMPARE_OP_FLOAT_r01 668 -#define _COMPARE_OP_FLOAT_r11 669 -#define _COMPARE_OP_FLOAT_r21 670 -#define _COMPARE_OP_FLOAT_r32 671 -#define _COMPARE_OP_INT_r23 672 -#define _COMPARE_OP_STR_r21 673 -#define _CONTAINS_OP_r21 674 -#define _CONTAINS_OP_DICT_r21 675 -#define _CONTAINS_OP_SET_r21 676 -#define _CONVERT_VALUE_r11 677 -#define _COPY_r01 678 -#define _COPY_1_r02 679 -#define _COPY_1_r12 680 -#define _COPY_1_r23 681 -#define _COPY_2_r03 682 -#define _COPY_2_r13 683 -#define _COPY_2_r23 684 -#define _COPY_3_r03 685 -#define _COPY_3_r13 686 -#define _COPY_3_r23 687 -#define _COPY_3_r33 688 -#define _COPY_FREE_VARS_r00 689 -#define _COPY_FREE_VARS_r11 690 -#define _COPY_FREE_VARS_r22 691 -#define _COPY_FREE_VARS_r33 692 -#define _CREATE_INIT_FRAME_r01 693 -#define _DELETE_ATTR_r10 694 -#define _DELETE_DEREF_r00 695 -#define _DELETE_FAST_r00 696 -#define _DELETE_GLOBAL_r00 697 -#define _DELETE_NAME_r00 698 -#define _DELETE_SUBSCR_r20 699 -#define _DEOPT_r00 700 -#define _DEOPT_r10 701 -#define _DEOPT_r20 702 -#define _DEOPT_r30 703 -#define _DICT_MERGE_r10 704 -#define _DICT_UPDATE_r10 705 -#define _DO_CALL_r01 706 -#define _DO_CALL_FUNCTION_EX_r31 707 -#define _DO_CALL_KW_r11 708 -#define _DYNAMIC_EXIT_r00 709 -#define _DYNAMIC_EXIT_r10 710 -#define _DYNAMIC_EXIT_r20 711 -#define _DYNAMIC_EXIT_r30 712 -#define _END_FOR_r10 713 -#define _END_SEND_r21 714 -#define _ERROR_POP_N_r00 715 -#define _EXIT_INIT_CHECK_r10 716 -#define _EXIT_TRACE_r00 717 -#define _EXIT_TRACE_r10 718 -#define _EXIT_TRACE_r20 719 -#define _EXIT_TRACE_r30 720 -#define _EXPAND_METHOD_r00 721 -#define _EXPAND_METHOD_KW_r11 722 -#define _FATAL_ERROR_r00 723 -#define _FATAL_ERROR_r11 724 -#define _FATAL_ERROR_r22 725 -#define _FATAL_ERROR_r33 726 -#define _FORMAT_SIMPLE_r11 727 -#define _FORMAT_WITH_SPEC_r21 728 -#define _FOR_ITER_r23 729 -#define _FOR_ITER_GEN_FRAME_r23 730 -#define _FOR_ITER_TIER_TWO_r23 731 -#define _GET_AITER_r11 732 -#define _GET_ANEXT_r12 733 -#define _GET_AWAITABLE_r11 734 -#define _GET_ITER_r12 735 -#define _GET_LEN_r12 736 -#define _GET_YIELD_FROM_ITER_r11 737 -#define _GUARD_BINARY_OP_EXTEND_r22 738 -#define _GUARD_CALLABLE_ISINSTANCE_r03 739 -#define _GUARD_CALLABLE_ISINSTANCE_r13 740 -#define _GUARD_CALLABLE_ISINSTANCE_r23 741 -#define _GUARD_CALLABLE_ISINSTANCE_r33 742 -#define _GUARD_CALLABLE_LEN_r03 743 -#define _GUARD_CALLABLE_LEN_r13 744 -#define _GUARD_CALLABLE_LEN_r23 745 -#define _GUARD_CALLABLE_LEN_r33 746 -#define _GUARD_CALLABLE_LIST_APPEND_r03 747 -#define _GUARD_CALLABLE_LIST_APPEND_r13 748 -#define _GUARD_CALLABLE_LIST_APPEND_r23 749 -#define _GUARD_CALLABLE_LIST_APPEND_r33 750 -#define _GUARD_CALLABLE_STR_1_r03 751 -#define _GUARD_CALLABLE_STR_1_r13 752 -#define _GUARD_CALLABLE_STR_1_r23 753 -#define _GUARD_CALLABLE_STR_1_r33 754 -#define _GUARD_CALLABLE_TUPLE_1_r03 755 -#define _GUARD_CALLABLE_TUPLE_1_r13 756 -#define _GUARD_CALLABLE_TUPLE_1_r23 757 -#define _GUARD_CALLABLE_TUPLE_1_r33 758 -#define _GUARD_CALLABLE_TYPE_1_r03 759 -#define _GUARD_CALLABLE_TYPE_1_r13 760 -#define _GUARD_CALLABLE_TYPE_1_r23 761 -#define _GUARD_CALLABLE_TYPE_1_r33 762 -#define _GUARD_DORV_NO_DICT_r01 763 -#define _GUARD_DORV_NO_DICT_r11 764 -#define _GUARD_DORV_NO_DICT_r22 765 -#define _GUARD_DORV_NO_DICT_r33 766 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 767 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 768 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 769 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 770 -#define _GUARD_GLOBALS_VERSION_r00 771 -#define _GUARD_GLOBALS_VERSION_r11 772 -#define _GUARD_GLOBALS_VERSION_r22 773 -#define _GUARD_GLOBALS_VERSION_r33 774 -#define _GUARD_IP_RETURN_GENERATOR_r00 775 -#define _GUARD_IP_RETURN_GENERATOR_r11 776 -#define _GUARD_IP_RETURN_GENERATOR_r22 777 -#define _GUARD_IP_RETURN_GENERATOR_r33 778 -#define _GUARD_IP_RETURN_VALUE_r00 779 -#define _GUARD_IP_RETURN_VALUE_r11 780 -#define _GUARD_IP_RETURN_VALUE_r22 781 -#define _GUARD_IP_RETURN_VALUE_r33 782 -#define _GUARD_IP_YIELD_VALUE_r00 783 -#define _GUARD_IP_YIELD_VALUE_r11 784 -#define _GUARD_IP_YIELD_VALUE_r22 785 -#define _GUARD_IP_YIELD_VALUE_r33 786 -#define _GUARD_IP__PUSH_FRAME_r00 787 -#define _GUARD_IP__PUSH_FRAME_r11 788 -#define _GUARD_IP__PUSH_FRAME_r22 789 -#define _GUARD_IP__PUSH_FRAME_r33 790 -#define _GUARD_IS_FALSE_POP_r00 791 -#define _GUARD_IS_FALSE_POP_r10 792 -#define _GUARD_IS_FALSE_POP_r21 793 -#define _GUARD_IS_FALSE_POP_r32 794 -#define _GUARD_IS_NONE_POP_r00 795 -#define _GUARD_IS_NONE_POP_r10 796 -#define _GUARD_IS_NONE_POP_r21 797 -#define _GUARD_IS_NONE_POP_r32 798 -#define _GUARD_IS_NOT_NONE_POP_r10 799 -#define _GUARD_IS_TRUE_POP_r00 800 -#define _GUARD_IS_TRUE_POP_r10 801 -#define _GUARD_IS_TRUE_POP_r21 802 -#define _GUARD_IS_TRUE_POP_r32 803 -#define _GUARD_KEYS_VERSION_r01 804 -#define _GUARD_KEYS_VERSION_r11 805 -#define _GUARD_KEYS_VERSION_r22 806 -#define _GUARD_KEYS_VERSION_r33 807 -#define _GUARD_NOS_DICT_r02 808 -#define _GUARD_NOS_DICT_r12 809 -#define _GUARD_NOS_DICT_r22 810 -#define _GUARD_NOS_DICT_r33 811 -#define _GUARD_NOS_FLOAT_r02 812 -#define _GUARD_NOS_FLOAT_r12 813 -#define _GUARD_NOS_FLOAT_r22 814 -#define _GUARD_NOS_FLOAT_r33 815 -#define _GUARD_NOS_INT_r02 816 -#define _GUARD_NOS_INT_r12 817 -#define _GUARD_NOS_INT_r22 818 -#define _GUARD_NOS_INT_r33 819 -#define _GUARD_NOS_LIST_r02 820 -#define _GUARD_NOS_LIST_r12 821 -#define _GUARD_NOS_LIST_r22 822 -#define _GUARD_NOS_LIST_r33 823 -#define _GUARD_NOS_NOT_NULL_r02 824 -#define _GUARD_NOS_NOT_NULL_r12 825 -#define _GUARD_NOS_NOT_NULL_r22 826 -#define _GUARD_NOS_NOT_NULL_r33 827 -#define _GUARD_NOS_NULL_r02 828 -#define _GUARD_NOS_NULL_r12 829 -#define _GUARD_NOS_NULL_r22 830 -#define _GUARD_NOS_NULL_r33 831 -#define _GUARD_NOS_OVERFLOWED_r02 832 -#define _GUARD_NOS_OVERFLOWED_r12 833 -#define _GUARD_NOS_OVERFLOWED_r22 834 -#define _GUARD_NOS_OVERFLOWED_r33 835 -#define _GUARD_NOS_TUPLE_r02 836 -#define _GUARD_NOS_TUPLE_r12 837 -#define _GUARD_NOS_TUPLE_r22 838 -#define _GUARD_NOS_TUPLE_r33 839 -#define _GUARD_NOS_UNICODE_r02 840 -#define _GUARD_NOS_UNICODE_r12 841 -#define _GUARD_NOS_UNICODE_r22 842 -#define _GUARD_NOS_UNICODE_r33 843 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 844 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 845 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 846 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 847 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 848 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 849 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 850 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 851 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 852 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 853 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 854 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 855 -#define _GUARD_THIRD_NULL_r03 856 -#define _GUARD_THIRD_NULL_r13 857 -#define _GUARD_THIRD_NULL_r23 858 -#define _GUARD_THIRD_NULL_r33 859 -#define _GUARD_TOS_ANY_SET_r01 860 -#define _GUARD_TOS_ANY_SET_r11 861 -#define _GUARD_TOS_ANY_SET_r22 862 -#define _GUARD_TOS_ANY_SET_r33 863 -#define _GUARD_TOS_DICT_r01 864 -#define _GUARD_TOS_DICT_r11 865 -#define _GUARD_TOS_DICT_r22 866 -#define _GUARD_TOS_DICT_r33 867 -#define _GUARD_TOS_FLOAT_r01 868 -#define _GUARD_TOS_FLOAT_r11 869 -#define _GUARD_TOS_FLOAT_r22 870 -#define _GUARD_TOS_FLOAT_r33 871 -#define _GUARD_TOS_INT_r01 872 -#define _GUARD_TOS_INT_r11 873 -#define _GUARD_TOS_INT_r22 874 -#define _GUARD_TOS_INT_r33 875 -#define _GUARD_TOS_LIST_r01 876 -#define _GUARD_TOS_LIST_r11 877 -#define _GUARD_TOS_LIST_r22 878 -#define _GUARD_TOS_LIST_r33 879 -#define _GUARD_TOS_OVERFLOWED_r01 880 -#define _GUARD_TOS_OVERFLOWED_r11 881 -#define _GUARD_TOS_OVERFLOWED_r22 882 -#define _GUARD_TOS_OVERFLOWED_r33 883 -#define _GUARD_TOS_SLICE_r01 884 -#define _GUARD_TOS_SLICE_r11 885 -#define _GUARD_TOS_SLICE_r22 886 -#define _GUARD_TOS_SLICE_r33 887 -#define _GUARD_TOS_TUPLE_r01 888 -#define _GUARD_TOS_TUPLE_r11 889 -#define _GUARD_TOS_TUPLE_r22 890 -#define _GUARD_TOS_TUPLE_r33 891 -#define _GUARD_TOS_UNICODE_r01 892 -#define _GUARD_TOS_UNICODE_r11 893 -#define _GUARD_TOS_UNICODE_r22 894 -#define _GUARD_TOS_UNICODE_r33 895 -#define _GUARD_TYPE_VERSION_r01 896 -#define _GUARD_TYPE_VERSION_r11 897 -#define _GUARD_TYPE_VERSION_r22 898 -#define _GUARD_TYPE_VERSION_r33 899 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 900 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 901 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 902 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 903 -#define _HANDLE_PENDING_AND_DEOPT_r00 904 -#define _HANDLE_PENDING_AND_DEOPT_r10 905 -#define _HANDLE_PENDING_AND_DEOPT_r20 906 -#define _HANDLE_PENDING_AND_DEOPT_r30 907 -#define _IMPORT_FROM_r12 908 -#define _IMPORT_NAME_r21 909 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 910 -#define _INIT_CALL_PY_EXACT_ARGS_r01 911 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 912 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 913 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 914 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 915 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 916 -#define _INSERT_NULL_r10 917 -#define _INSTRUMENTED_FOR_ITER_r23 918 -#define _INSTRUMENTED_INSTRUCTION_r00 919 -#define _INSTRUMENTED_JUMP_FORWARD_r00 920 -#define _INSTRUMENTED_JUMP_FORWARD_r11 921 -#define _INSTRUMENTED_JUMP_FORWARD_r22 922 -#define _INSTRUMENTED_JUMP_FORWARD_r33 923 -#define _INSTRUMENTED_LINE_r00 924 -#define _INSTRUMENTED_NOT_TAKEN_r00 925 -#define _INSTRUMENTED_NOT_TAKEN_r11 926 -#define _INSTRUMENTED_NOT_TAKEN_r22 927 -#define _INSTRUMENTED_NOT_TAKEN_r33 928 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 929 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 930 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 931 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 932 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 933 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 934 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 935 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 936 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 937 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 938 -#define _IS_NONE_r11 939 -#define _IS_OP_r21 940 -#define _ITER_CHECK_LIST_r02 941 -#define _ITER_CHECK_LIST_r12 942 -#define _ITER_CHECK_LIST_r22 943 -#define _ITER_CHECK_LIST_r33 944 -#define _ITER_CHECK_RANGE_r02 945 -#define _ITER_CHECK_RANGE_r12 946 -#define _ITER_CHECK_RANGE_r22 947 -#define _ITER_CHECK_RANGE_r33 948 -#define _ITER_CHECK_TUPLE_r02 949 -#define _ITER_CHECK_TUPLE_r12 950 -#define _ITER_CHECK_TUPLE_r22 951 -#define _ITER_CHECK_TUPLE_r33 952 -#define _ITER_JUMP_LIST_r02 953 -#define _ITER_JUMP_LIST_r12 954 -#define _ITER_JUMP_LIST_r22 955 -#define _ITER_JUMP_LIST_r33 956 -#define _ITER_JUMP_RANGE_r02 957 -#define _ITER_JUMP_RANGE_r12 958 -#define _ITER_JUMP_RANGE_r22 959 -#define _ITER_JUMP_RANGE_r33 960 -#define _ITER_JUMP_TUPLE_r02 961 -#define _ITER_JUMP_TUPLE_r12 962 -#define _ITER_JUMP_TUPLE_r22 963 -#define _ITER_JUMP_TUPLE_r33 964 -#define _ITER_NEXT_LIST_r23 965 -#define _ITER_NEXT_LIST_TIER_TWO_r23 966 -#define _ITER_NEXT_RANGE_r03 967 -#define _ITER_NEXT_RANGE_r13 968 -#define _ITER_NEXT_RANGE_r23 969 -#define _ITER_NEXT_TUPLE_r03 970 -#define _ITER_NEXT_TUPLE_r13 971 -#define _ITER_NEXT_TUPLE_r23 972 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 973 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 974 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 975 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 976 -#define _JUMP_TO_TOP_r00 977 -#define _LIST_APPEND_r10 978 -#define _LIST_EXTEND_r10 979 -#define _LOAD_ATTR_r10 980 -#define _LOAD_ATTR_CLASS_r11 981 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 982 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 983 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 984 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 985 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 986 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 987 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 988 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 989 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 990 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 991 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 992 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 993 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 994 -#define _LOAD_ATTR_MODULE_r11 995 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 996 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 997 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 998 -#define _LOAD_ATTR_SLOT_r11 999 -#define _LOAD_ATTR_WITH_HINT_r11 1000 -#define _LOAD_BUILD_CLASS_r01 1001 -#define _LOAD_BYTECODE_r00 1002 -#define _LOAD_COMMON_CONSTANT_r01 1003 -#define _LOAD_COMMON_CONSTANT_r12 1004 -#define _LOAD_COMMON_CONSTANT_r23 1005 -#define _LOAD_CONST_r01 1006 -#define _LOAD_CONST_r12 1007 -#define _LOAD_CONST_r23 1008 -#define _LOAD_CONST_INLINE_r01 1009 -#define _LOAD_CONST_INLINE_r12 1010 -#define _LOAD_CONST_INLINE_r23 1011 -#define _LOAD_CONST_INLINE_BORROW_r01 1012 -#define _LOAD_CONST_INLINE_BORROW_r12 1013 -#define _LOAD_CONST_INLINE_BORROW_r23 1014 -#define _LOAD_CONST_UNDER_INLINE_r02 1015 -#define _LOAD_CONST_UNDER_INLINE_r12 1016 -#define _LOAD_CONST_UNDER_INLINE_r23 1017 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1018 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1019 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1020 -#define _LOAD_DEREF_r01 1021 -#define _LOAD_FAST_r01 1022 -#define _LOAD_FAST_r12 1023 -#define _LOAD_FAST_r23 1024 -#define _LOAD_FAST_0_r01 1025 -#define _LOAD_FAST_0_r12 1026 -#define _LOAD_FAST_0_r23 1027 -#define _LOAD_FAST_1_r01 1028 -#define _LOAD_FAST_1_r12 1029 -#define _LOAD_FAST_1_r23 1030 -#define _LOAD_FAST_2_r01 1031 -#define _LOAD_FAST_2_r12 1032 -#define _LOAD_FAST_2_r23 1033 -#define _LOAD_FAST_3_r01 1034 -#define _LOAD_FAST_3_r12 1035 -#define _LOAD_FAST_3_r23 1036 -#define _LOAD_FAST_4_r01 1037 -#define _LOAD_FAST_4_r12 1038 -#define _LOAD_FAST_4_r23 1039 -#define _LOAD_FAST_5_r01 1040 -#define _LOAD_FAST_5_r12 1041 -#define _LOAD_FAST_5_r23 1042 -#define _LOAD_FAST_6_r01 1043 -#define _LOAD_FAST_6_r12 1044 -#define _LOAD_FAST_6_r23 1045 -#define _LOAD_FAST_7_r01 1046 -#define _LOAD_FAST_7_r12 1047 -#define _LOAD_FAST_7_r23 1048 -#define _LOAD_FAST_AND_CLEAR_r01 1049 -#define _LOAD_FAST_AND_CLEAR_r12 1050 -#define _LOAD_FAST_AND_CLEAR_r23 1051 -#define _LOAD_FAST_BORROW_r01 1052 -#define _LOAD_FAST_BORROW_r12 1053 -#define _LOAD_FAST_BORROW_r23 1054 -#define _LOAD_FAST_BORROW_0_r01 1055 -#define _LOAD_FAST_BORROW_0_r12 1056 -#define _LOAD_FAST_BORROW_0_r23 1057 -#define _LOAD_FAST_BORROW_1_r01 1058 -#define _LOAD_FAST_BORROW_1_r12 1059 -#define _LOAD_FAST_BORROW_1_r23 1060 -#define _LOAD_FAST_BORROW_2_r01 1061 -#define _LOAD_FAST_BORROW_2_r12 1062 -#define _LOAD_FAST_BORROW_2_r23 1063 -#define _LOAD_FAST_BORROW_3_r01 1064 -#define _LOAD_FAST_BORROW_3_r12 1065 -#define _LOAD_FAST_BORROW_3_r23 1066 -#define _LOAD_FAST_BORROW_4_r01 1067 -#define _LOAD_FAST_BORROW_4_r12 1068 -#define _LOAD_FAST_BORROW_4_r23 1069 -#define _LOAD_FAST_BORROW_5_r01 1070 -#define _LOAD_FAST_BORROW_5_r12 1071 -#define _LOAD_FAST_BORROW_5_r23 1072 -#define _LOAD_FAST_BORROW_6_r01 1073 -#define _LOAD_FAST_BORROW_6_r12 1074 -#define _LOAD_FAST_BORROW_6_r23 1075 -#define _LOAD_FAST_BORROW_7_r01 1076 -#define _LOAD_FAST_BORROW_7_r12 1077 -#define _LOAD_FAST_BORROW_7_r23 1078 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1079 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1080 -#define _LOAD_FAST_CHECK_r01 1081 -#define _LOAD_FAST_CHECK_r12 1082 -#define _LOAD_FAST_CHECK_r23 1083 -#define _LOAD_FAST_LOAD_FAST_r02 1084 -#define _LOAD_FAST_LOAD_FAST_r13 1085 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1086 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1087 -#define _LOAD_GLOBAL_r00 1088 -#define _LOAD_GLOBAL_BUILTINS_r01 1089 -#define _LOAD_GLOBAL_MODULE_r01 1090 -#define _LOAD_LOCALS_r01 1091 -#define _LOAD_LOCALS_r12 1092 -#define _LOAD_LOCALS_r23 1093 -#define _LOAD_NAME_r01 1094 -#define _LOAD_SMALL_INT_r01 1095 -#define _LOAD_SMALL_INT_r12 1096 -#define _LOAD_SMALL_INT_r23 1097 -#define _LOAD_SMALL_INT_0_r01 1098 -#define _LOAD_SMALL_INT_0_r12 1099 -#define _LOAD_SMALL_INT_0_r23 1100 -#define _LOAD_SMALL_INT_1_r01 1101 -#define _LOAD_SMALL_INT_1_r12 1102 -#define _LOAD_SMALL_INT_1_r23 1103 -#define _LOAD_SMALL_INT_2_r01 1104 -#define _LOAD_SMALL_INT_2_r12 1105 -#define _LOAD_SMALL_INT_2_r23 1106 -#define _LOAD_SMALL_INT_3_r01 1107 -#define _LOAD_SMALL_INT_3_r12 1108 -#define _LOAD_SMALL_INT_3_r23 1109 -#define _LOAD_SPECIAL_r00 1110 -#define _LOAD_SUPER_ATTR_ATTR_r31 1111 -#define _LOAD_SUPER_ATTR_METHOD_r32 1112 -#define _MAKE_CALLARGS_A_TUPLE_r33 1113 -#define _MAKE_CELL_r00 1114 -#define _MAKE_FUNCTION_r11 1115 -#define _MAKE_WARM_r00 1116 -#define _MAKE_WARM_r11 1117 -#define _MAKE_WARM_r22 1118 -#define _MAKE_WARM_r33 1119 -#define _MAP_ADD_r20 1120 -#define _MATCH_CLASS_r31 1121 -#define _MATCH_KEYS_r23 1122 -#define _MATCH_MAPPING_r02 1123 -#define _MATCH_MAPPING_r12 1124 -#define _MATCH_MAPPING_r23 1125 -#define _MATCH_SEQUENCE_r02 1126 -#define _MATCH_SEQUENCE_r12 1127 -#define _MATCH_SEQUENCE_r23 1128 -#define _MAYBE_EXPAND_METHOD_r00 1129 -#define _MAYBE_EXPAND_METHOD_KW_r11 1130 -#define _MONITOR_CALL_r00 1131 -#define _MONITOR_CALL_KW_r11 1132 -#define _MONITOR_JUMP_BACKWARD_r00 1133 -#define _MONITOR_JUMP_BACKWARD_r11 1134 -#define _MONITOR_JUMP_BACKWARD_r22 1135 -#define _MONITOR_JUMP_BACKWARD_r33 1136 -#define _MONITOR_RESUME_r00 1137 -#define _NOP_r00 1138 -#define _NOP_r11 1139 -#define _NOP_r22 1140 -#define _NOP_r33 1141 -#define _POP_CALL_r20 1142 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1143 -#define _POP_CALL_ONE_r30 1144 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1145 -#define _POP_CALL_TWO_r30 1146 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1147 -#define _POP_EXCEPT_r10 1148 -#define _POP_ITER_r20 1149 -#define _POP_JUMP_IF_FALSE_r00 1150 -#define _POP_JUMP_IF_FALSE_r10 1151 -#define _POP_JUMP_IF_FALSE_r21 1152 -#define _POP_JUMP_IF_FALSE_r32 1153 -#define _POP_JUMP_IF_TRUE_r00 1154 -#define _POP_JUMP_IF_TRUE_r10 1155 -#define _POP_JUMP_IF_TRUE_r21 1156 -#define _POP_JUMP_IF_TRUE_r32 1157 -#define _POP_TOP_r10 1158 -#define _POP_TOP_FLOAT_r00 1159 -#define _POP_TOP_FLOAT_r10 1160 -#define _POP_TOP_FLOAT_r21 1161 -#define _POP_TOP_FLOAT_r32 1162 -#define _POP_TOP_INT_r00 1163 -#define _POP_TOP_INT_r10 1164 -#define _POP_TOP_INT_r21 1165 -#define _POP_TOP_INT_r32 1166 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1167 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1168 -#define _POP_TOP_NOP_r00 1169 -#define _POP_TOP_NOP_r10 1170 -#define _POP_TOP_NOP_r21 1171 -#define _POP_TOP_NOP_r32 1172 -#define _POP_TOP_UNICODE_r00 1173 -#define _POP_TOP_UNICODE_r10 1174 -#define _POP_TOP_UNICODE_r21 1175 -#define _POP_TOP_UNICODE_r32 1176 -#define _POP_TWO_r20 1177 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1178 -#define _PUSH_EXC_INFO_r02 1179 -#define _PUSH_EXC_INFO_r12 1180 -#define _PUSH_EXC_INFO_r23 1181 -#define _PUSH_FRAME_r10 1182 -#define _PUSH_NULL_r01 1183 -#define _PUSH_NULL_r12 1184 -#define _PUSH_NULL_r23 1185 -#define _PUSH_NULL_CONDITIONAL_r00 1186 -#define _PY_FRAME_GENERAL_r01 1187 -#define _PY_FRAME_KW_r11 1188 -#define _QUICKEN_RESUME_r00 1189 -#define _QUICKEN_RESUME_r11 1190 -#define _QUICKEN_RESUME_r22 1191 -#define _QUICKEN_RESUME_r33 1192 -#define _REPLACE_WITH_TRUE_r11 1193 -#define _RESUME_CHECK_r00 1194 -#define _RESUME_CHECK_r11 1195 -#define _RESUME_CHECK_r22 1196 -#define _RESUME_CHECK_r33 1197 -#define _RETURN_GENERATOR_r01 1198 -#define _RETURN_VALUE_r11 1199 -#define _SAVE_RETURN_OFFSET_r00 1200 -#define _SAVE_RETURN_OFFSET_r11 1201 -#define _SAVE_RETURN_OFFSET_r22 1202 -#define _SAVE_RETURN_OFFSET_r33 1203 -#define _SEND_r22 1204 -#define _SEND_GEN_FRAME_r22 1205 -#define _SETUP_ANNOTATIONS_r00 1206 -#define _SET_ADD_r10 1207 -#define _SET_FUNCTION_ATTRIBUTE_r01 1208 -#define _SET_FUNCTION_ATTRIBUTE_r11 1209 -#define _SET_FUNCTION_ATTRIBUTE_r21 1210 -#define _SET_FUNCTION_ATTRIBUTE_r32 1211 -#define _SET_IP_r00 1212 -#define _SET_IP_r11 1213 -#define _SET_IP_r22 1214 -#define _SET_IP_r33 1215 -#define _SET_UPDATE_r10 1216 -#define _SPILL_OR_RELOAD_r01 1217 -#define _SPILL_OR_RELOAD_r02 1218 -#define _SPILL_OR_RELOAD_r03 1219 -#define _SPILL_OR_RELOAD_r10 1220 -#define _SPILL_OR_RELOAD_r12 1221 -#define _SPILL_OR_RELOAD_r13 1222 -#define _SPILL_OR_RELOAD_r20 1223 -#define _SPILL_OR_RELOAD_r21 1224 -#define _SPILL_OR_RELOAD_r23 1225 -#define _SPILL_OR_RELOAD_r30 1226 -#define _SPILL_OR_RELOAD_r31 1227 -#define _SPILL_OR_RELOAD_r32 1228 -#define _START_EXECUTOR_r00 1229 -#define _STORE_ATTR_r20 1230 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1231 -#define _STORE_ATTR_SLOT_r21 1232 -#define _STORE_ATTR_WITH_HINT_r21 1233 -#define _STORE_DEREF_r10 1234 -#define _STORE_FAST_r10 1235 -#define _STORE_FAST_0_r10 1236 -#define _STORE_FAST_1_r10 1237 -#define _STORE_FAST_2_r10 1238 -#define _STORE_FAST_3_r10 1239 -#define _STORE_FAST_4_r10 1240 -#define _STORE_FAST_5_r10 1241 -#define _STORE_FAST_6_r10 1242 -#define _STORE_FAST_7_r10 1243 -#define _STORE_FAST_LOAD_FAST_r11 1244 -#define _STORE_FAST_STORE_FAST_r20 1245 -#define _STORE_GLOBAL_r10 1246 -#define _STORE_NAME_r10 1247 -#define _STORE_SLICE_r30 1248 -#define _STORE_SUBSCR_r30 1249 -#define _STORE_SUBSCR_DICT_r31 1250 -#define _STORE_SUBSCR_LIST_INT_r32 1251 -#define _SWAP_r11 1252 -#define _SWAP_2_r02 1253 -#define _SWAP_2_r12 1254 -#define _SWAP_2_r22 1255 -#define _SWAP_2_r33 1256 -#define _SWAP_3_r03 1257 -#define _SWAP_3_r13 1258 -#define _SWAP_3_r23 1259 -#define _SWAP_3_r33 1260 -#define _TIER2_RESUME_CHECK_r00 1261 -#define _TIER2_RESUME_CHECK_r11 1262 -#define _TIER2_RESUME_CHECK_r22 1263 -#define _TIER2_RESUME_CHECK_r33 1264 -#define _TO_BOOL_r11 1265 -#define _TO_BOOL_BOOL_r01 1266 -#define _TO_BOOL_BOOL_r11 1267 -#define _TO_BOOL_BOOL_r22 1268 -#define _TO_BOOL_BOOL_r33 1269 -#define _TO_BOOL_INT_r11 1270 -#define _TO_BOOL_LIST_r11 1271 -#define _TO_BOOL_NONE_r01 1272 -#define _TO_BOOL_NONE_r11 1273 -#define _TO_BOOL_NONE_r22 1274 -#define _TO_BOOL_NONE_r33 1275 -#define _TO_BOOL_STR_r11 1276 -#define _TRACE_RECORD_r00 1277 -#define _UNARY_INVERT_r11 1278 -#define _UNARY_NEGATIVE_r11 1279 -#define _UNARY_NOT_r01 1280 -#define _UNARY_NOT_r11 1281 -#define _UNARY_NOT_r22 1282 -#define _UNARY_NOT_r33 1283 -#define _UNPACK_EX_r10 1284 -#define _UNPACK_SEQUENCE_r10 1285 -#define _UNPACK_SEQUENCE_LIST_r10 1286 -#define _UNPACK_SEQUENCE_TUPLE_r10 1287 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1288 -#define _WITH_EXCEPT_START_r33 1289 -#define _YIELD_VALUE_r11 1290 -#define MAX_UOP_REGS_ID 1290 +#define MAX_UOP_ID 554 +#define _BINARY_OP_r21 555 +#define _BINARY_OP_ADD_FLOAT_r03 556 +#define _BINARY_OP_ADD_FLOAT_r13 557 +#define _BINARY_OP_ADD_FLOAT_r23 558 +#define _BINARY_OP_ADD_INT_r03 559 +#define _BINARY_OP_ADD_INT_r13 560 +#define _BINARY_OP_ADD_INT_r23 561 +#define _BINARY_OP_ADD_UNICODE_r03 562 +#define _BINARY_OP_ADD_UNICODE_r13 563 +#define _BINARY_OP_ADD_UNICODE_r23 564 +#define _BINARY_OP_EXTEND_r21 565 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r20 566 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 567 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 568 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 569 +#define _BINARY_OP_MULTIPLY_INT_r03 570 +#define _BINARY_OP_MULTIPLY_INT_r13 571 +#define _BINARY_OP_MULTIPLY_INT_r23 572 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 573 +#define _BINARY_OP_SUBSCR_DICT_r21 574 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 575 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 576 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 577 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 578 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 579 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 580 +#define _BINARY_OP_SUBSCR_STR_INT_r23 581 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r21 582 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 583 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 584 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 585 +#define _BINARY_OP_SUBTRACT_INT_r03 586 +#define _BINARY_OP_SUBTRACT_INT_r13 587 +#define _BINARY_OP_SUBTRACT_INT_r23 588 +#define _BINARY_SLICE_r31 589 +#define _BUILD_INTERPOLATION_r01 590 +#define _BUILD_LIST_r01 591 +#define _BUILD_MAP_r01 592 +#define _BUILD_SET_r01 593 +#define _BUILD_SLICE_r01 594 +#define _BUILD_STRING_r01 595 +#define _BUILD_TEMPLATE_r21 596 +#define _BUILD_TUPLE_r01 597 +#define _CALL_BUILTIN_CLASS_r01 598 +#define _CALL_BUILTIN_FAST_r01 599 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 600 +#define _CALL_BUILTIN_O_r03 601 +#define _CALL_INTRINSIC_1_r11 602 +#define _CALL_INTRINSIC_2_r21 603 +#define _CALL_ISINSTANCE_r31 604 +#define _CALL_KW_NON_PY_r11 605 +#define _CALL_LEN_r33 606 +#define _CALL_LIST_APPEND_r02 607 +#define _CALL_LIST_APPEND_r12 608 +#define _CALL_LIST_APPEND_r22 609 +#define _CALL_LIST_APPEND_r32 610 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 611 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 612 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 613 +#define _CALL_METHOD_DESCRIPTOR_O_r01 614 +#define _CALL_NON_PY_GENERAL_r01 615 +#define _CALL_STR_1_r32 616 +#define _CALL_TUPLE_1_r32 617 +#define _CALL_TYPE_1_r31 618 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 619 +#define _CHECK_ATTR_CLASS_r01 620 +#define _CHECK_ATTR_CLASS_r11 621 +#define _CHECK_ATTR_CLASS_r22 622 +#define _CHECK_ATTR_CLASS_r33 623 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 624 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 625 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 626 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 627 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 628 +#define _CHECK_EG_MATCH_r22 629 +#define _CHECK_EXC_MATCH_r22 630 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 631 +#define _CHECK_FUNCTION_VERSION_r00 632 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 633 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 634 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 635 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 636 +#define _CHECK_FUNCTION_VERSION_KW_r11 637 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 638 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 639 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 640 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 641 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 642 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 643 +#define _CHECK_METHOD_VERSION_r00 644 +#define _CHECK_METHOD_VERSION_KW_r11 645 +#define _CHECK_PEP_523_r00 646 +#define _CHECK_PEP_523_r11 647 +#define _CHECK_PEP_523_r22 648 +#define _CHECK_PEP_523_r33 649 +#define _CHECK_PERIODIC_r00 650 +#define _CHECK_PERIODIC_AT_END_r00 651 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 652 +#define _CHECK_RECURSION_REMAINING_r00 653 +#define _CHECK_RECURSION_REMAINING_r11 654 +#define _CHECK_RECURSION_REMAINING_r22 655 +#define _CHECK_RECURSION_REMAINING_r33 656 +#define _CHECK_STACK_SPACE_r00 657 +#define _CHECK_STACK_SPACE_OPERAND_r00 658 +#define _CHECK_STACK_SPACE_OPERAND_r11 659 +#define _CHECK_STACK_SPACE_OPERAND_r22 660 +#define _CHECK_STACK_SPACE_OPERAND_r33 661 +#define _CHECK_VALIDITY_r00 662 +#define _CHECK_VALIDITY_r11 663 +#define _CHECK_VALIDITY_r22 664 +#define _CHECK_VALIDITY_r33 665 +#define _COLD_DYNAMIC_EXIT_r00 666 +#define _COLD_EXIT_r00 667 +#define _COMPARE_OP_r21 668 +#define _COMPARE_OP_FLOAT_r01 669 +#define _COMPARE_OP_FLOAT_r11 670 +#define _COMPARE_OP_FLOAT_r21 671 +#define _COMPARE_OP_FLOAT_r32 672 +#define _COMPARE_OP_INT_r23 673 +#define _COMPARE_OP_STR_r21 674 +#define _CONTAINS_OP_r21 675 +#define _CONTAINS_OP_DICT_r21 676 +#define _CONTAINS_OP_SET_r21 677 +#define _CONVERT_VALUE_r11 678 +#define _COPY_r01 679 +#define _COPY_1_r02 680 +#define _COPY_1_r12 681 +#define _COPY_1_r23 682 +#define _COPY_2_r03 683 +#define _COPY_2_r13 684 +#define _COPY_2_r23 685 +#define _COPY_3_r03 686 +#define _COPY_3_r13 687 +#define _COPY_3_r23 688 +#define _COPY_3_r33 689 +#define _COPY_FREE_VARS_r00 690 +#define _COPY_FREE_VARS_r11 691 +#define _COPY_FREE_VARS_r22 692 +#define _COPY_FREE_VARS_r33 693 +#define _CREATE_INIT_FRAME_r01 694 +#define _DELETE_ATTR_r10 695 +#define _DELETE_DEREF_r00 696 +#define _DELETE_FAST_r00 697 +#define _DELETE_GLOBAL_r00 698 +#define _DELETE_NAME_r00 699 +#define _DELETE_SUBSCR_r20 700 +#define _DEOPT_r00 701 +#define _DEOPT_r10 702 +#define _DEOPT_r20 703 +#define _DEOPT_r30 704 +#define _DICT_MERGE_r10 705 +#define _DICT_UPDATE_r10 706 +#define _DO_CALL_r01 707 +#define _DO_CALL_FUNCTION_EX_r31 708 +#define _DO_CALL_KW_r11 709 +#define _DYNAMIC_EXIT_r00 710 +#define _DYNAMIC_EXIT_r10 711 +#define _DYNAMIC_EXIT_r20 712 +#define _DYNAMIC_EXIT_r30 713 +#define _END_FOR_r10 714 +#define _END_SEND_r21 715 +#define _ERROR_POP_N_r00 716 +#define _EXIT_INIT_CHECK_r10 717 +#define _EXIT_TRACE_r00 718 +#define _EXIT_TRACE_r10 719 +#define _EXIT_TRACE_r20 720 +#define _EXIT_TRACE_r30 721 +#define _EXPAND_METHOD_r00 722 +#define _EXPAND_METHOD_KW_r11 723 +#define _FATAL_ERROR_r00 724 +#define _FATAL_ERROR_r11 725 +#define _FATAL_ERROR_r22 726 +#define _FATAL_ERROR_r33 727 +#define _FORMAT_SIMPLE_r11 728 +#define _FORMAT_WITH_SPEC_r21 729 +#define _FOR_ITER_r23 730 +#define _FOR_ITER_GEN_FRAME_r23 731 +#define _FOR_ITER_TIER_TWO_r23 732 +#define _GET_AITER_r11 733 +#define _GET_ANEXT_r12 734 +#define _GET_AWAITABLE_r11 735 +#define _GET_ITER_r12 736 +#define _GET_LEN_r12 737 +#define _GET_YIELD_FROM_ITER_r11 738 +#define _GUARD_BINARY_OP_EXTEND_r22 739 +#define _GUARD_CALLABLE_ISINSTANCE_r03 740 +#define _GUARD_CALLABLE_ISINSTANCE_r13 741 +#define _GUARD_CALLABLE_ISINSTANCE_r23 742 +#define _GUARD_CALLABLE_ISINSTANCE_r33 743 +#define _GUARD_CALLABLE_LEN_r03 744 +#define _GUARD_CALLABLE_LEN_r13 745 +#define _GUARD_CALLABLE_LEN_r23 746 +#define _GUARD_CALLABLE_LEN_r33 747 +#define _GUARD_CALLABLE_LIST_APPEND_r03 748 +#define _GUARD_CALLABLE_LIST_APPEND_r13 749 +#define _GUARD_CALLABLE_LIST_APPEND_r23 750 +#define _GUARD_CALLABLE_LIST_APPEND_r33 751 +#define _GUARD_CALLABLE_STR_1_r03 752 +#define _GUARD_CALLABLE_STR_1_r13 753 +#define _GUARD_CALLABLE_STR_1_r23 754 +#define _GUARD_CALLABLE_STR_1_r33 755 +#define _GUARD_CALLABLE_TUPLE_1_r03 756 +#define _GUARD_CALLABLE_TUPLE_1_r13 757 +#define _GUARD_CALLABLE_TUPLE_1_r23 758 +#define _GUARD_CALLABLE_TUPLE_1_r33 759 +#define _GUARD_CALLABLE_TYPE_1_r03 760 +#define _GUARD_CALLABLE_TYPE_1_r13 761 +#define _GUARD_CALLABLE_TYPE_1_r23 762 +#define _GUARD_CALLABLE_TYPE_1_r33 763 +#define _GUARD_DORV_NO_DICT_r01 764 +#define _GUARD_DORV_NO_DICT_r11 765 +#define _GUARD_DORV_NO_DICT_r22 766 +#define _GUARD_DORV_NO_DICT_r33 767 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 768 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 769 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 770 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 771 +#define _GUARD_GLOBALS_VERSION_r00 772 +#define _GUARD_GLOBALS_VERSION_r11 773 +#define _GUARD_GLOBALS_VERSION_r22 774 +#define _GUARD_GLOBALS_VERSION_r33 775 +#define _GUARD_IP_RETURN_GENERATOR_r00 776 +#define _GUARD_IP_RETURN_GENERATOR_r11 777 +#define _GUARD_IP_RETURN_GENERATOR_r22 778 +#define _GUARD_IP_RETURN_GENERATOR_r33 779 +#define _GUARD_IP_RETURN_VALUE_r00 780 +#define _GUARD_IP_RETURN_VALUE_r11 781 +#define _GUARD_IP_RETURN_VALUE_r22 782 +#define _GUARD_IP_RETURN_VALUE_r33 783 +#define _GUARD_IP_YIELD_VALUE_r00 784 +#define _GUARD_IP_YIELD_VALUE_r11 785 +#define _GUARD_IP_YIELD_VALUE_r22 786 +#define _GUARD_IP_YIELD_VALUE_r33 787 +#define _GUARD_IP__PUSH_FRAME_r00 788 +#define _GUARD_IP__PUSH_FRAME_r11 789 +#define _GUARD_IP__PUSH_FRAME_r22 790 +#define _GUARD_IP__PUSH_FRAME_r33 791 +#define _GUARD_IS_FALSE_POP_r00 792 +#define _GUARD_IS_FALSE_POP_r10 793 +#define _GUARD_IS_FALSE_POP_r21 794 +#define _GUARD_IS_FALSE_POP_r32 795 +#define _GUARD_IS_NONE_POP_r00 796 +#define _GUARD_IS_NONE_POP_r10 797 +#define _GUARD_IS_NONE_POP_r21 798 +#define _GUARD_IS_NONE_POP_r32 799 +#define _GUARD_IS_NOT_NONE_POP_r10 800 +#define _GUARD_IS_TRUE_POP_r00 801 +#define _GUARD_IS_TRUE_POP_r10 802 +#define _GUARD_IS_TRUE_POP_r21 803 +#define _GUARD_IS_TRUE_POP_r32 804 +#define _GUARD_KEYS_VERSION_r01 805 +#define _GUARD_KEYS_VERSION_r11 806 +#define _GUARD_KEYS_VERSION_r22 807 +#define _GUARD_KEYS_VERSION_r33 808 +#define _GUARD_NOS_DICT_r02 809 +#define _GUARD_NOS_DICT_r12 810 +#define _GUARD_NOS_DICT_r22 811 +#define _GUARD_NOS_DICT_r33 812 +#define _GUARD_NOS_FLOAT_r02 813 +#define _GUARD_NOS_FLOAT_r12 814 +#define _GUARD_NOS_FLOAT_r22 815 +#define _GUARD_NOS_FLOAT_r33 816 +#define _GUARD_NOS_INT_r02 817 +#define _GUARD_NOS_INT_r12 818 +#define _GUARD_NOS_INT_r22 819 +#define _GUARD_NOS_INT_r33 820 +#define _GUARD_NOS_LIST_r02 821 +#define _GUARD_NOS_LIST_r12 822 +#define _GUARD_NOS_LIST_r22 823 +#define _GUARD_NOS_LIST_r33 824 +#define _GUARD_NOS_NOT_NULL_r02 825 +#define _GUARD_NOS_NOT_NULL_r12 826 +#define _GUARD_NOS_NOT_NULL_r22 827 +#define _GUARD_NOS_NOT_NULL_r33 828 +#define _GUARD_NOS_NULL_r02 829 +#define _GUARD_NOS_NULL_r12 830 +#define _GUARD_NOS_NULL_r22 831 +#define _GUARD_NOS_NULL_r33 832 +#define _GUARD_NOS_OVERFLOWED_r02 833 +#define _GUARD_NOS_OVERFLOWED_r12 834 +#define _GUARD_NOS_OVERFLOWED_r22 835 +#define _GUARD_NOS_OVERFLOWED_r33 836 +#define _GUARD_NOS_TUPLE_r02 837 +#define _GUARD_NOS_TUPLE_r12 838 +#define _GUARD_NOS_TUPLE_r22 839 +#define _GUARD_NOS_TUPLE_r33 840 +#define _GUARD_NOS_UNICODE_r02 841 +#define _GUARD_NOS_UNICODE_r12 842 +#define _GUARD_NOS_UNICODE_r22 843 +#define _GUARD_NOS_UNICODE_r33 844 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 845 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 846 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 847 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 848 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 849 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 850 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 851 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 852 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 853 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 854 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 855 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 856 +#define _GUARD_THIRD_NULL_r03 857 +#define _GUARD_THIRD_NULL_r13 858 +#define _GUARD_THIRD_NULL_r23 859 +#define _GUARD_THIRD_NULL_r33 860 +#define _GUARD_TOS_ANY_SET_r01 861 +#define _GUARD_TOS_ANY_SET_r11 862 +#define _GUARD_TOS_ANY_SET_r22 863 +#define _GUARD_TOS_ANY_SET_r33 864 +#define _GUARD_TOS_DICT_r01 865 +#define _GUARD_TOS_DICT_r11 866 +#define _GUARD_TOS_DICT_r22 867 +#define _GUARD_TOS_DICT_r33 868 +#define _GUARD_TOS_FLOAT_r01 869 +#define _GUARD_TOS_FLOAT_r11 870 +#define _GUARD_TOS_FLOAT_r22 871 +#define _GUARD_TOS_FLOAT_r33 872 +#define _GUARD_TOS_INT_r01 873 +#define _GUARD_TOS_INT_r11 874 +#define _GUARD_TOS_INT_r22 875 +#define _GUARD_TOS_INT_r33 876 +#define _GUARD_TOS_LIST_r01 877 +#define _GUARD_TOS_LIST_r11 878 +#define _GUARD_TOS_LIST_r22 879 +#define _GUARD_TOS_LIST_r33 880 +#define _GUARD_TOS_OVERFLOWED_r01 881 +#define _GUARD_TOS_OVERFLOWED_r11 882 +#define _GUARD_TOS_OVERFLOWED_r22 883 +#define _GUARD_TOS_OVERFLOWED_r33 884 +#define _GUARD_TOS_SLICE_r01 885 +#define _GUARD_TOS_SLICE_r11 886 +#define _GUARD_TOS_SLICE_r22 887 +#define _GUARD_TOS_SLICE_r33 888 +#define _GUARD_TOS_TUPLE_r01 889 +#define _GUARD_TOS_TUPLE_r11 890 +#define _GUARD_TOS_TUPLE_r22 891 +#define _GUARD_TOS_TUPLE_r33 892 +#define _GUARD_TOS_UNICODE_r01 893 +#define _GUARD_TOS_UNICODE_r11 894 +#define _GUARD_TOS_UNICODE_r22 895 +#define _GUARD_TOS_UNICODE_r33 896 +#define _GUARD_TYPE_VERSION_r01 897 +#define _GUARD_TYPE_VERSION_r11 898 +#define _GUARD_TYPE_VERSION_r22 899 +#define _GUARD_TYPE_VERSION_r33 900 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 901 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 902 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 903 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 904 +#define _HANDLE_PENDING_AND_DEOPT_r00 905 +#define _HANDLE_PENDING_AND_DEOPT_r10 906 +#define _HANDLE_PENDING_AND_DEOPT_r20 907 +#define _HANDLE_PENDING_AND_DEOPT_r30 908 +#define _IMPORT_FROM_r12 909 +#define _IMPORT_NAME_r21 910 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 911 +#define _INIT_CALL_PY_EXACT_ARGS_r01 912 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 913 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 914 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 915 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 916 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 917 +#define _INSERT_NULL_r10 918 +#define _INSTRUMENTED_FOR_ITER_r23 919 +#define _INSTRUMENTED_INSTRUCTION_r00 920 +#define _INSTRUMENTED_JUMP_FORWARD_r00 921 +#define _INSTRUMENTED_JUMP_FORWARD_r11 922 +#define _INSTRUMENTED_JUMP_FORWARD_r22 923 +#define _INSTRUMENTED_JUMP_FORWARD_r33 924 +#define _INSTRUMENTED_LINE_r00 925 +#define _INSTRUMENTED_NOT_TAKEN_r00 926 +#define _INSTRUMENTED_NOT_TAKEN_r11 927 +#define _INSTRUMENTED_NOT_TAKEN_r22 928 +#define _INSTRUMENTED_NOT_TAKEN_r33 929 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 930 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 931 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 932 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 933 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 934 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 935 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 936 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 937 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 938 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 939 +#define _IS_NONE_r11 940 +#define _IS_OP_r21 941 +#define _ITER_CHECK_LIST_r02 942 +#define _ITER_CHECK_LIST_r12 943 +#define _ITER_CHECK_LIST_r22 944 +#define _ITER_CHECK_LIST_r33 945 +#define _ITER_CHECK_RANGE_r02 946 +#define _ITER_CHECK_RANGE_r12 947 +#define _ITER_CHECK_RANGE_r22 948 +#define _ITER_CHECK_RANGE_r33 949 +#define _ITER_CHECK_TUPLE_r02 950 +#define _ITER_CHECK_TUPLE_r12 951 +#define _ITER_CHECK_TUPLE_r22 952 +#define _ITER_CHECK_TUPLE_r33 953 +#define _ITER_JUMP_LIST_r02 954 +#define _ITER_JUMP_LIST_r12 955 +#define _ITER_JUMP_LIST_r22 956 +#define _ITER_JUMP_LIST_r33 957 +#define _ITER_JUMP_RANGE_r02 958 +#define _ITER_JUMP_RANGE_r12 959 +#define _ITER_JUMP_RANGE_r22 960 +#define _ITER_JUMP_RANGE_r33 961 +#define _ITER_JUMP_TUPLE_r02 962 +#define _ITER_JUMP_TUPLE_r12 963 +#define _ITER_JUMP_TUPLE_r22 964 +#define _ITER_JUMP_TUPLE_r33 965 +#define _ITER_NEXT_LIST_r23 966 +#define _ITER_NEXT_LIST_TIER_TWO_r23 967 +#define _ITER_NEXT_RANGE_r03 968 +#define _ITER_NEXT_RANGE_r13 969 +#define _ITER_NEXT_RANGE_r23 970 +#define _ITER_NEXT_TUPLE_r03 971 +#define _ITER_NEXT_TUPLE_r13 972 +#define _ITER_NEXT_TUPLE_r23 973 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 974 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 975 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 976 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 977 +#define _JUMP_TO_TOP_r00 978 +#define _LIST_APPEND_r10 979 +#define _LIST_EXTEND_r10 980 +#define _LOAD_ATTR_r10 981 +#define _LOAD_ATTR_CLASS_r11 982 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 983 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 984 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 985 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 986 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 987 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 988 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 989 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 990 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 991 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 992 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 993 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 994 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 995 +#define _LOAD_ATTR_MODULE_r11 996 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 997 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 998 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 999 +#define _LOAD_ATTR_SLOT_r11 1000 +#define _LOAD_ATTR_WITH_HINT_r11 1001 +#define _LOAD_BUILD_CLASS_r01 1002 +#define _LOAD_BYTECODE_r00 1003 +#define _LOAD_COMMON_CONSTANT_r01 1004 +#define _LOAD_COMMON_CONSTANT_r12 1005 +#define _LOAD_COMMON_CONSTANT_r23 1006 +#define _LOAD_CONST_r01 1007 +#define _LOAD_CONST_r12 1008 +#define _LOAD_CONST_r23 1009 +#define _LOAD_CONST_INLINE_r01 1010 +#define _LOAD_CONST_INLINE_r12 1011 +#define _LOAD_CONST_INLINE_r23 1012 +#define _LOAD_CONST_INLINE_BORROW_r01 1013 +#define _LOAD_CONST_INLINE_BORROW_r12 1014 +#define _LOAD_CONST_INLINE_BORROW_r23 1015 +#define _LOAD_CONST_UNDER_INLINE_r02 1016 +#define _LOAD_CONST_UNDER_INLINE_r12 1017 +#define _LOAD_CONST_UNDER_INLINE_r23 1018 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1019 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1020 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1021 +#define _LOAD_DEREF_r01 1022 +#define _LOAD_FAST_r01 1023 +#define _LOAD_FAST_r12 1024 +#define _LOAD_FAST_r23 1025 +#define _LOAD_FAST_0_r01 1026 +#define _LOAD_FAST_0_r12 1027 +#define _LOAD_FAST_0_r23 1028 +#define _LOAD_FAST_1_r01 1029 +#define _LOAD_FAST_1_r12 1030 +#define _LOAD_FAST_1_r23 1031 +#define _LOAD_FAST_2_r01 1032 +#define _LOAD_FAST_2_r12 1033 +#define _LOAD_FAST_2_r23 1034 +#define _LOAD_FAST_3_r01 1035 +#define _LOAD_FAST_3_r12 1036 +#define _LOAD_FAST_3_r23 1037 +#define _LOAD_FAST_4_r01 1038 +#define _LOAD_FAST_4_r12 1039 +#define _LOAD_FAST_4_r23 1040 +#define _LOAD_FAST_5_r01 1041 +#define _LOAD_FAST_5_r12 1042 +#define _LOAD_FAST_5_r23 1043 +#define _LOAD_FAST_6_r01 1044 +#define _LOAD_FAST_6_r12 1045 +#define _LOAD_FAST_6_r23 1046 +#define _LOAD_FAST_7_r01 1047 +#define _LOAD_FAST_7_r12 1048 +#define _LOAD_FAST_7_r23 1049 +#define _LOAD_FAST_AND_CLEAR_r01 1050 +#define _LOAD_FAST_AND_CLEAR_r12 1051 +#define _LOAD_FAST_AND_CLEAR_r23 1052 +#define _LOAD_FAST_BORROW_r01 1053 +#define _LOAD_FAST_BORROW_r12 1054 +#define _LOAD_FAST_BORROW_r23 1055 +#define _LOAD_FAST_BORROW_0_r01 1056 +#define _LOAD_FAST_BORROW_0_r12 1057 +#define _LOAD_FAST_BORROW_0_r23 1058 +#define _LOAD_FAST_BORROW_1_r01 1059 +#define _LOAD_FAST_BORROW_1_r12 1060 +#define _LOAD_FAST_BORROW_1_r23 1061 +#define _LOAD_FAST_BORROW_2_r01 1062 +#define _LOAD_FAST_BORROW_2_r12 1063 +#define _LOAD_FAST_BORROW_2_r23 1064 +#define _LOAD_FAST_BORROW_3_r01 1065 +#define _LOAD_FAST_BORROW_3_r12 1066 +#define _LOAD_FAST_BORROW_3_r23 1067 +#define _LOAD_FAST_BORROW_4_r01 1068 +#define _LOAD_FAST_BORROW_4_r12 1069 +#define _LOAD_FAST_BORROW_4_r23 1070 +#define _LOAD_FAST_BORROW_5_r01 1071 +#define _LOAD_FAST_BORROW_5_r12 1072 +#define _LOAD_FAST_BORROW_5_r23 1073 +#define _LOAD_FAST_BORROW_6_r01 1074 +#define _LOAD_FAST_BORROW_6_r12 1075 +#define _LOAD_FAST_BORROW_6_r23 1076 +#define _LOAD_FAST_BORROW_7_r01 1077 +#define _LOAD_FAST_BORROW_7_r12 1078 +#define _LOAD_FAST_BORROW_7_r23 1079 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1080 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1081 +#define _LOAD_FAST_CHECK_r01 1082 +#define _LOAD_FAST_CHECK_r12 1083 +#define _LOAD_FAST_CHECK_r23 1084 +#define _LOAD_FAST_LOAD_FAST_r02 1085 +#define _LOAD_FAST_LOAD_FAST_r13 1086 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1087 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1088 +#define _LOAD_GLOBAL_r00 1089 +#define _LOAD_GLOBAL_BUILTINS_r01 1090 +#define _LOAD_GLOBAL_MODULE_r01 1091 +#define _LOAD_LOCALS_r01 1092 +#define _LOAD_LOCALS_r12 1093 +#define _LOAD_LOCALS_r23 1094 +#define _LOAD_NAME_r01 1095 +#define _LOAD_SMALL_INT_r01 1096 +#define _LOAD_SMALL_INT_r12 1097 +#define _LOAD_SMALL_INT_r23 1098 +#define _LOAD_SMALL_INT_0_r01 1099 +#define _LOAD_SMALL_INT_0_r12 1100 +#define _LOAD_SMALL_INT_0_r23 1101 +#define _LOAD_SMALL_INT_1_r01 1102 +#define _LOAD_SMALL_INT_1_r12 1103 +#define _LOAD_SMALL_INT_1_r23 1104 +#define _LOAD_SMALL_INT_2_r01 1105 +#define _LOAD_SMALL_INT_2_r12 1106 +#define _LOAD_SMALL_INT_2_r23 1107 +#define _LOAD_SMALL_INT_3_r01 1108 +#define _LOAD_SMALL_INT_3_r12 1109 +#define _LOAD_SMALL_INT_3_r23 1110 +#define _LOAD_SPECIAL_r00 1111 +#define _LOAD_SUPER_ATTR_ATTR_r31 1112 +#define _LOAD_SUPER_ATTR_METHOD_r32 1113 +#define _MAKE_CALLARGS_A_TUPLE_r33 1114 +#define _MAKE_CELL_r00 1115 +#define _MAKE_FUNCTION_r11 1116 +#define _MAKE_WARM_r00 1117 +#define _MAKE_WARM_r11 1118 +#define _MAKE_WARM_r22 1119 +#define _MAKE_WARM_r33 1120 +#define _MAP_ADD_r20 1121 +#define _MATCH_CLASS_r31 1122 +#define _MATCH_KEYS_r23 1123 +#define _MATCH_MAPPING_r02 1124 +#define _MATCH_MAPPING_r12 1125 +#define _MATCH_MAPPING_r23 1126 +#define _MATCH_SEQUENCE_r02 1127 +#define _MATCH_SEQUENCE_r12 1128 +#define _MATCH_SEQUENCE_r23 1129 +#define _MAYBE_EXPAND_METHOD_r00 1130 +#define _MAYBE_EXPAND_METHOD_KW_r11 1131 +#define _MONITOR_CALL_r00 1132 +#define _MONITOR_CALL_KW_r11 1133 +#define _MONITOR_JUMP_BACKWARD_r00 1134 +#define _MONITOR_JUMP_BACKWARD_r11 1135 +#define _MONITOR_JUMP_BACKWARD_r22 1136 +#define _MONITOR_JUMP_BACKWARD_r33 1137 +#define _MONITOR_RESUME_r00 1138 +#define _NOP_r00 1139 +#define _NOP_r11 1140 +#define _NOP_r22 1141 +#define _NOP_r33 1142 +#define _POP_CALL_r20 1143 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1144 +#define _POP_CALL_ONE_r30 1145 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1146 +#define _POP_CALL_TWO_r30 1147 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1148 +#define _POP_EXCEPT_r10 1149 +#define _POP_ITER_r20 1150 +#define _POP_JUMP_IF_FALSE_r00 1151 +#define _POP_JUMP_IF_FALSE_r10 1152 +#define _POP_JUMP_IF_FALSE_r21 1153 +#define _POP_JUMP_IF_FALSE_r32 1154 +#define _POP_JUMP_IF_TRUE_r00 1155 +#define _POP_JUMP_IF_TRUE_r10 1156 +#define _POP_JUMP_IF_TRUE_r21 1157 +#define _POP_JUMP_IF_TRUE_r32 1158 +#define _POP_TOP_r10 1159 +#define _POP_TOP_FLOAT_r00 1160 +#define _POP_TOP_FLOAT_r10 1161 +#define _POP_TOP_FLOAT_r21 1162 +#define _POP_TOP_FLOAT_r32 1163 +#define _POP_TOP_INT_r00 1164 +#define _POP_TOP_INT_r10 1165 +#define _POP_TOP_INT_r21 1166 +#define _POP_TOP_INT_r32 1167 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1168 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1169 +#define _POP_TOP_NOP_r00 1170 +#define _POP_TOP_NOP_r10 1171 +#define _POP_TOP_NOP_r21 1172 +#define _POP_TOP_NOP_r32 1173 +#define _POP_TOP_UNICODE_r00 1174 +#define _POP_TOP_UNICODE_r10 1175 +#define _POP_TOP_UNICODE_r21 1176 +#define _POP_TOP_UNICODE_r32 1177 +#define _POP_TWO_r20 1178 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1179 +#define _PUSH_EXC_INFO_r02 1180 +#define _PUSH_EXC_INFO_r12 1181 +#define _PUSH_EXC_INFO_r23 1182 +#define _PUSH_FRAME_r10 1183 +#define _PUSH_NULL_r01 1184 +#define _PUSH_NULL_r12 1185 +#define _PUSH_NULL_r23 1186 +#define _PUSH_NULL_CONDITIONAL_r00 1187 +#define _PY_FRAME_GENERAL_r01 1188 +#define _PY_FRAME_KW_r11 1189 +#define _QUICKEN_RESUME_r00 1190 +#define _QUICKEN_RESUME_r11 1191 +#define _QUICKEN_RESUME_r22 1192 +#define _QUICKEN_RESUME_r33 1193 +#define _REPLACE_WITH_TRUE_r11 1194 +#define _RESUME_CHECK_r00 1195 +#define _RESUME_CHECK_r11 1196 +#define _RESUME_CHECK_r22 1197 +#define _RESUME_CHECK_r33 1198 +#define _RETURN_GENERATOR_r01 1199 +#define _RETURN_VALUE_r11 1200 +#define _SAVE_RETURN_OFFSET_r00 1201 +#define _SAVE_RETURN_OFFSET_r11 1202 +#define _SAVE_RETURN_OFFSET_r22 1203 +#define _SAVE_RETURN_OFFSET_r33 1204 +#define _SEND_r22 1205 +#define _SEND_GEN_FRAME_r22 1206 +#define _SETUP_ANNOTATIONS_r00 1207 +#define _SET_ADD_r10 1208 +#define _SET_FUNCTION_ATTRIBUTE_r01 1209 +#define _SET_FUNCTION_ATTRIBUTE_r11 1210 +#define _SET_FUNCTION_ATTRIBUTE_r21 1211 +#define _SET_FUNCTION_ATTRIBUTE_r32 1212 +#define _SET_IP_r00 1213 +#define _SET_IP_r11 1214 +#define _SET_IP_r22 1215 +#define _SET_IP_r33 1216 +#define _SET_UPDATE_r10 1217 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1218 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1219 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1220 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1221 +#define _SPILL_OR_RELOAD_r01 1222 +#define _SPILL_OR_RELOAD_r02 1223 +#define _SPILL_OR_RELOAD_r03 1224 +#define _SPILL_OR_RELOAD_r10 1225 +#define _SPILL_OR_RELOAD_r12 1226 +#define _SPILL_OR_RELOAD_r13 1227 +#define _SPILL_OR_RELOAD_r20 1228 +#define _SPILL_OR_RELOAD_r21 1229 +#define _SPILL_OR_RELOAD_r23 1230 +#define _SPILL_OR_RELOAD_r30 1231 +#define _SPILL_OR_RELOAD_r31 1232 +#define _SPILL_OR_RELOAD_r32 1233 +#define _START_EXECUTOR_r00 1234 +#define _STORE_ATTR_r20 1235 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1236 +#define _STORE_ATTR_SLOT_r21 1237 +#define _STORE_ATTR_WITH_HINT_r21 1238 +#define _STORE_DEREF_r10 1239 +#define _STORE_FAST_r10 1240 +#define _STORE_FAST_0_r10 1241 +#define _STORE_FAST_1_r10 1242 +#define _STORE_FAST_2_r10 1243 +#define _STORE_FAST_3_r10 1244 +#define _STORE_FAST_4_r10 1245 +#define _STORE_FAST_5_r10 1246 +#define _STORE_FAST_6_r10 1247 +#define _STORE_FAST_7_r10 1248 +#define _STORE_FAST_LOAD_FAST_r11 1249 +#define _STORE_FAST_STORE_FAST_r20 1250 +#define _STORE_GLOBAL_r10 1251 +#define _STORE_NAME_r10 1252 +#define _STORE_SLICE_r30 1253 +#define _STORE_SUBSCR_r30 1254 +#define _STORE_SUBSCR_DICT_r31 1255 +#define _STORE_SUBSCR_LIST_INT_r32 1256 +#define _SWAP_r11 1257 +#define _SWAP_2_r02 1258 +#define _SWAP_2_r12 1259 +#define _SWAP_2_r22 1260 +#define _SWAP_2_r33 1261 +#define _SWAP_3_r03 1262 +#define _SWAP_3_r13 1263 +#define _SWAP_3_r23 1264 +#define _SWAP_3_r33 1265 +#define _TIER2_RESUME_CHECK_r00 1266 +#define _TIER2_RESUME_CHECK_r11 1267 +#define _TIER2_RESUME_CHECK_r22 1268 +#define _TIER2_RESUME_CHECK_r33 1269 +#define _TO_BOOL_r11 1270 +#define _TO_BOOL_BOOL_r01 1271 +#define _TO_BOOL_BOOL_r11 1272 +#define _TO_BOOL_BOOL_r22 1273 +#define _TO_BOOL_BOOL_r33 1274 +#define _TO_BOOL_INT_r11 1275 +#define _TO_BOOL_LIST_r11 1276 +#define _TO_BOOL_NONE_r01 1277 +#define _TO_BOOL_NONE_r11 1278 +#define _TO_BOOL_NONE_r22 1279 +#define _TO_BOOL_NONE_r33 1280 +#define _TO_BOOL_STR_r11 1281 +#define _TRACE_RECORD_r00 1282 +#define _UNARY_INVERT_r11 1283 +#define _UNARY_NEGATIVE_r11 1284 +#define _UNARY_NOT_r01 1285 +#define _UNARY_NOT_r11 1286 +#define _UNARY_NOT_r22 1287 +#define _UNARY_NOT_r33 1288 +#define _UNPACK_EX_r10 1289 +#define _UNPACK_SEQUENCE_r10 1290 +#define _UNPACK_SEQUENCE_LIST_r10 1291 +#define _UNPACK_SEQUENCE_TUPLE_r10 1292 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1293 +#define _WITH_EXCEPT_START_r33 1294 +#define _YIELD_VALUE_r11 1295 +#define MAX_UOP_REGS_ID 1295 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 3a6bf7b3d76a8f..1281eeb041daab 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -335,6 +335,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_POP_TWO_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG, [_POP_CALL_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG, [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW] = 0, [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG, [_LOAD_CONST_UNDER_INLINE] = 0, [_LOAD_CONST_UNDER_INLINE_BORROW] = 0, @@ -3065,6 +3066,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { 1, 3, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 }, }, }, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 3, 0, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 }, + { 3, 1, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 }, + { 3, 2, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 }, + { 3, 3, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 }, + }, + }, [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW] = { .best = { 3, 3, 3, 3 }, .entries = { @@ -3817,6 +3827,10 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_POP_TWO_LOAD_CONST_INLINE_BORROW_r21] = _POP_TWO_LOAD_CONST_INLINE_BORROW, [_POP_CALL_LOAD_CONST_INLINE_BORROW_r21] = _POP_CALL_LOAD_CONST_INLINE_BORROW, [_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31] = _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03] = _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13] = _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23] = _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33] = _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, [_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31] = _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, [_LOAD_CONST_UNDER_INLINE_r02] = _LOAD_CONST_UNDER_INLINE, [_LOAD_CONST_UNDER_INLINE_r12] = _LOAD_CONST_UNDER_INLINE, @@ -4762,6 +4776,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_SET_IP_r33] = "_SET_IP_r33", [_SET_UPDATE] = "_SET_UPDATE", [_SET_UPDATE_r10] = "_SET_UPDATE_r10", + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW] = "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW", + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03] = "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03", + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13] = "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13", + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23] = "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23", + [_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33] = "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33", [_SPILL_OR_RELOAD] = "_SPILL_OR_RELOAD", [_SPILL_OR_RELOAD_r01] = "_SPILL_OR_RELOAD_r01", [_SPILL_OR_RELOAD_r02] = "_SPILL_OR_RELOAD_r02", @@ -5479,6 +5498,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 2; case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW: return 3; + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW: + return 3; case _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW: return 4; case _LOAD_CONST_UNDER_INLINE: diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 88ac1664fe5ddf..9a822834c14f36 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3008,6 +3008,18 @@ class Obj: for _ in range(TIER2_THRESHOLD+1): obj.attr = EvilAttr(obj.__dict__) + def test_constant_fold_tuple(self): + def testfunc(n): + for _ in range(n): + t = (1,) + p = len(t) + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertNotIn("_CALL_LEN", uops) + def test_binary_subscr_list_int(self): def testfunc(n): l = [1] diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-19-00-59-29.gh-issue-142961.q8WRSq.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-19-00-59-29.gh-issue-142961.q8WRSq.rst new file mode 100644 index 00000000000000..4b75ab232d50e4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-19-00-59-29.gh-issue-142961.q8WRSq.rst @@ -0,0 +1 @@ +Fix a segfault in the JIT when constant folding ``len(tuple)``. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4ce7968ddc2929..1291fe56a59d5b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5285,6 +5285,13 @@ dummy_func( value = PyStackRef_FromPyObjectBorrow(ptr); } + tier2 op(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, (ptr/4, callable, null, arg -- res, a, c)) { + res = PyStackRef_FromPyObjectBorrow(ptr); + a = arg; + c = callable; + INPUTS_DEAD(); + } + tier2 op(_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, (ptr/4, callable, null, pop1, pop2 -- value)) { PyStackRef_CLOSE(pop2); PyStackRef_CLOSE(pop1); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 74bd939c87d4ec..2305df6ad5aaf1 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -16532,6 +16532,106 @@ break; } + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef callable; + _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + arg = stack_pointer[-1]; + callable = stack_pointer[-3]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectBorrow(ptr); + a = arg; + c = callable; + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -3; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef callable; + _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef _stack_item_0 = _tos_cache0; + arg = _stack_item_0; + callable = stack_pointer[-2]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectBorrow(ptr); + a = arg; + c = callable; + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef callable; + _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + arg = _stack_item_1; + callable = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectBorrow(ptr); + a = arg; + c = callable; + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef arg; + _PyStackRef callable; + _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + arg = _stack_item_2; + callable = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectBorrow(ptr); + a = arg; + c = callable; + _tos_cache2 = c; + _tos_cache1 = a; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31: { CHECK_CURRENT_CACHED_VALUES(3); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index f36139db954cb8..d2527fd85e3f12 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -529,10 +529,6 @@ dummy_func(void) { value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); } - op(_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, (ptr/4, unused, unused, unused -- value)) { - value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); - } - op(_POP_CALL_TWO_LOAD_CONST_INLINE_BORROW, (ptr/4, unused, unused, unused, unused -- value)) { value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); } @@ -1263,7 +1259,7 @@ dummy_func(void) { goto error; } if (_Py_IsImmortal(temp)) { - REPLACE_OP(this_instr, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, + REPLACE_OP(this_instr, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); } res = sym_new_const(ctx, temp); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 69a2a32e4f15df..0389c6192e1cac 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2862,7 +2862,7 @@ goto error; } if (_Py_IsImmortal(temp)) { - REPLACE_OP(this_instr, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW, + REPLACE_OP(this_instr, _SHUFFLE_3_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); } res = sym_new_const(ctx, temp); @@ -3424,8 +3424,7 @@ case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW: { JitOptRef value; - PyObject *ptr = (PyObject *)this_instr->operand0; - value = PyJitRef_Borrow(sym_new_const(ctx, ptr)); + value = sym_new_not_null(ctx); CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = value; stack_pointer += -2; @@ -3433,6 +3432,19 @@ break; } + case _SHUFFLE_3_LOAD_CONST_INLINE_BORROW: { + JitOptRef res; + JitOptRef a; + JitOptRef c; + res = sym_new_not_null(ctx); + a = sym_new_not_null(ctx); + c = sym_new_not_null(ctx); + stack_pointer[-3] = res; + stack_pointer[-2] = a; + stack_pointer[-1] = c; + break; + } + case _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW: { JitOptRef value; PyObject *ptr = (PyObject *)this_instr->operand0; From 6a4f10325d58deb1906b39d68dc8e84f4c2bf5a4 Mon Sep 17 00:00:00 2001 From: stratakis Date: Fri, 19 Dec 2025 19:14:52 +0100 Subject: [PATCH 023/105] gh-142776: Ensure fp file descriptor is closed on all code paths in import.c (GH-142777) --- .../2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst | 1 + Python/import.c | 14 ++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst new file mode 100644 index 00000000000000..3039b04d89cb88 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-18-01-00-14.gh-issue-142776.ACaoeP.rst @@ -0,0 +1 @@ +Fix a file descriptor leak in import.c diff --git a/Python/import.c b/Python/import.c index db433dbc971d76..466c5868ab7ee8 100644 --- a/Python/import.c +++ b/Python/import.c @@ -4762,6 +4762,7 @@ static PyObject * _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /*[clinic end generated code: output=83249b827a4fde77 input=c31b954f4cf4e09d]*/ { + FILE *fp = NULL; PyObject *mod = NULL; PyThreadState *tstate = _PyThreadState_GET(); @@ -4804,16 +4805,12 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) /* We would move this (and the fclose() below) into * _PyImport_GetModuleExportHooks(), but it isn't clear if the intervening * code relies on fp still being open. */ - FILE *fp; if (file != NULL) { fp = Py_fopen(info.filename, "r"); if (fp == NULL) { goto finally; } } - else { - fp = NULL; - } PyModInitFunction p0 = NULL; PyModExportFunction ex0 = NULL; @@ -4822,7 +4819,7 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) mod = import_run_modexport(tstate, ex0, &info, spec); // Modules created from slots handle GIL enablement (Py_mod_gil slot) // when they're created. - goto cleanup; + goto finally; } if (p0 == NULL) { goto finally; @@ -4845,13 +4842,10 @@ _imp_create_dynamic_impl(PyObject *module, PyObject *spec, PyObject *file) } #endif -cleanup: - // XXX Shouldn't this happen in the error cases too (i.e. in "finally")? - if (fp) { +finally: + if (fp != NULL) { fclose(fp); } - -finally: _Py_ext_module_loader_info_clear(&info); return mod; } From 6b4bc6e6a240966cfec488c25c83c40a101a94c8 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 20 Dec 2025 03:06:34 +0800 Subject: [PATCH 024/105] gh-134584: JIT: Borrow references for immortal promoted globals (GH-142921) JIT: Borrow references for immortal promoted globals --- Lib/test/test_capi/test_opt.py | 38 ++++++++++++++++++++++++++++++++++ Python/optimizer_bytecodes.c | 14 +++++++++++-- Python/optimizer_cases.c.h | 14 +++++++++++-- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 9a822834c14f36..3ea93277dab295 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3008,6 +3008,44 @@ class Obj: for _ in range(TIER2_THRESHOLD+1): obj.attr = EvilAttr(obj.__dict__) + def test_promoted_global_refcount_eliminated(self): + result = script_helper.run_python_until_end('-c', textwrap.dedent(""" + import _testinternalcapi + import opcode + import _opcode + + def get_first_executor(func): + code = func.__code__ + co_code = code.co_code + for i in range(0, len(co_code), 2): + try: + return _opcode.get_executor(code, i) + except ValueError: + pass + return None + + def get_opnames(ex): + return {item[0] for item in ex} + + + def testfunc(n): + y = [] + for i in range(n): + x = tuple(y) + return x + + testfunc(_testinternalcapi.TIER2_THRESHOLD) + + ex = get_first_executor(testfunc) + assert ex is not None + uops = get_opnames(ex) + assert "_LOAD_GLOBAL_BUILTIN" not in uops + assert "_LOAD_CONST_INLINE_BORROW" in uops + assert "_POP_TOP_NOP" in uops + assert "_POP_TOP" not in uops + """), PYTHON_JIT="1") + self.assertEqual(result[0].rc, 0, result) + def test_constant_fold_tuple(self): def testfunc(n): for _ in range(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index d2527fd85e3f12..cd789db1fe89d2 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1376,7 +1376,12 @@ dummy_func(void) { res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } } @@ -1411,7 +1416,12 @@ dummy_func(void) { res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 0389c6192e1cac..85d3d041215103 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1330,7 +1330,12 @@ res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; @@ -1367,7 +1372,12 @@ res = sym_new_not_null(ctx); } else { - res = sym_new_const(ctx, cnst); + if (_Py_IsImmortal(cnst)) { + res = PyJitRef_Borrow(sym_new_const(ctx, cnst)); + } + else { + res = sym_new_const(ctx, cnst); + } } CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; From e2a7db717507a66b49bb796391530147b3acab93 Mon Sep 17 00:00:00 2001 From: Shamil Date: Fri, 19 Dec 2025 22:07:11 +0300 Subject: [PATCH 025/105] gh-142476: fix memory leak when creating JIT executors (GH-142492) --- .../2025-12-13-01-11-03.gh-issue-142476.44Sp4N.rst | 2 ++ Python/optimizer.c | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-13-01-11-03.gh-issue-142476.44Sp4N.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-13-01-11-03.gh-issue-142476.44Sp4N.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-13-01-11-03.gh-issue-142476.44Sp4N.rst new file mode 100644 index 00000000000000..eae1f3a1ce53b6 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-13-01-11-03.gh-issue-142476.44Sp4N.rst @@ -0,0 +1,2 @@ +Fix a memory leak in the experimental Tier 2 optimizer when creating +executors. Patched by Shamil Abdulaev. diff --git a/Python/optimizer.c b/Python/optimizer.c index 1e905850e3de6b..16abced6edbeec 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -185,12 +185,17 @@ _PyOptimizer_Optimize( else { executor->vm_data.code = NULL; } + executor->vm_data.chain_depth = chain_depth; + assert(executor->vm_data.valid); _PyExitData *exit = _tstate->jit_tracer_state.initial_state.exit; if (exit != NULL) { exit->executor = executor; } - executor->vm_data.chain_depth = chain_depth; - assert(executor->vm_data.valid); + else { + // An executor inserted into the code object now has a strong reference + // to it from the code object. Thus, we don't need this reference anymore. + Py_DECREF(executor); + } interp->compiling = false; return 1; #else From 08bc03ff2a5545a165ba57f4ca73b8ff705dc757 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 19 Dec 2025 14:10:37 -0500 Subject: [PATCH 026/105] gh-120321: Make gi_frame_state transitions atomic in FT build (gh-142599) This makes generator frame state transitions atomic in the free threading build, which avoids segfaults when trying to execute a generator from multiple threads concurrently. There are still a few operations that aren't thread-safe and may crash if performed concurrently on the same generator/coroutine: * Accessing gi_yieldfrom/cr_await/ag_await * Accessing gi_frame/cr_frame/ag_frame * Async generator operations --- Include/cpython/pyatomic.h | 3 + Include/cpython/pyatomic_gcc.h | 4 + Include/cpython/pyatomic_msc.h | 13 + Include/cpython/pyatomic_std.h | 8 + .../internal/pycore_pyatomic_ft_wrappers.h | 9 + Include/internal/pycore_tstate.h | 7 + Include/internal/pycore_uop_ids.h | 1134 +++++++++-------- Include/internal/pycore_uop_metadata.h | 10 +- .../test_free_threading/test_generators.py | 71 ++ Objects/genobject.c | 518 ++++---- Python/bytecodes.c | 19 +- Python/ceval.c | 15 +- Python/ceval_macros.h | 25 + Python/executor_cases.c.h | 94 +- Python/generated_cases.c.h | 22 +- Tools/cases_generator/analyzer.py | 1 + 16 files changed, 1097 insertions(+), 856 deletions(-) diff --git a/Include/cpython/pyatomic.h b/Include/cpython/pyatomic.h index 790640309f1e03..ce907fd6a4c453 100644 --- a/Include/cpython/pyatomic.h +++ b/Include/cpython/pyatomic.h @@ -523,6 +523,9 @@ _Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value); static inline void _Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value); +static inline void +_Py_atomic_store_int8_release(int8_t *obj, int8_t value); + static inline void _Py_atomic_store_int_release(int *obj, int value); diff --git a/Include/cpython/pyatomic_gcc.h b/Include/cpython/pyatomic_gcc.h index 1566b83b9f6a1b..c045213c898a03 100644 --- a/Include/cpython/pyatomic_gcc.h +++ b/Include/cpython/pyatomic_gcc.h @@ -572,6 +572,10 @@ static inline void _Py_atomic_store_int_release(int *obj, int value) { __atomic_store_n(obj, value, __ATOMIC_RELEASE); } +static inline void +_Py_atomic_store_int8_release(int8_t *obj, int8_t value) +{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); } + static inline void _Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value) { __atomic_store_n(obj, value, __ATOMIC_RELEASE); } diff --git a/Include/cpython/pyatomic_msc.h b/Include/cpython/pyatomic_msc.h index d155955df0cddf..8b9dd3eb0f8e16 100644 --- a/Include/cpython/pyatomic_msc.h +++ b/Include/cpython/pyatomic_msc.h @@ -1066,6 +1066,19 @@ _Py_atomic_store_int_release(int *obj, int value) #endif } +static inline void +_Py_atomic_store_int8_release(int8_t *obj, int8_t value) +{ +#if defined(_M_X64) || defined(_M_IX86) + *(int8_t volatile *)obj = value; +#elif defined(_M_ARM64) + _Py_atomic_ASSERT_ARG_TYPE(unsigned __int8); + __stlr8((unsigned __int8 volatile *)obj, (unsigned __int8)value); +#else +# error "no implementation of _Py_atomic_store_int8_release" +#endif +} + static inline void _Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value) { diff --git a/Include/cpython/pyatomic_std.h b/Include/cpython/pyatomic_std.h index 7176f667a4082c..cfc8dbefc63d09 100644 --- a/Include/cpython/pyatomic_std.h +++ b/Include/cpython/pyatomic_std.h @@ -1023,6 +1023,14 @@ _Py_atomic_store_int_release(int *obj, int value) memory_order_release); } +static inline void +_Py_atomic_store_int8_release(int8_t *obj, int8_t value) +{ + _Py_USING_STD; + atomic_store_explicit((_Atomic(int8_t)*)obj, value, + memory_order_release); +} + static inline void _Py_atomic_store_uint_release(unsigned int *obj, unsigned int value) { diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h index 1a6d5075361f3c..70a32db663b293 100644 --- a/Include/internal/pycore_pyatomic_ft_wrappers.h +++ b/Include/internal/pycore_pyatomic_ft_wrappers.h @@ -41,6 +41,8 @@ extern "C" { _Py_atomic_load_uint8(&value) #define FT_ATOMIC_STORE_UINT8(value, new_value) \ _Py_atomic_store_uint8(&value, new_value) +#define FT_ATOMIC_LOAD_INT8_RELAXED(value) \ + _Py_atomic_load_int8_relaxed(&value) #define FT_ATOMIC_LOAD_UINT8_RELAXED(value) \ _Py_atomic_load_uint8_relaxed(&value) #define FT_ATOMIC_LOAD_UINT16_RELAXED(value) \ @@ -55,6 +57,10 @@ extern "C" { _Py_atomic_store_ptr_release(&value, new_value) #define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) \ _Py_atomic_store_uintptr_release(&value, new_value) +#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) \ + _Py_atomic_store_int8_relaxed(&value, new_value) +#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) \ + _Py_atomic_store_int8_release(&value, new_value) #define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \ _Py_atomic_store_ssize_relaxed(&value, new_value) #define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \ @@ -134,6 +140,7 @@ extern "C" { #define FT_ATOMIC_LOAD_PTR_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT8(value) value #define FT_ATOMIC_STORE_UINT8(value, new_value) value = new_value +#define FT_ATOMIC_LOAD_INT8_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value #define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value @@ -141,6 +148,8 @@ extern "C" { #define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value +#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) value = new_value +#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value #define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value #define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index c4f723ac8abbbe..a57f1f45c135a6 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -82,6 +82,13 @@ typedef struct _PyThreadStateImpl { PyObject *asyncio_running_loop; // Strong reference PyObject *asyncio_running_task; // Strong reference + // Distinguishes between yield and return from PyEval_EvalFrame(). + // See gen_send_ex2() in Objects/genobject.c + enum { + GENERATOR_RETURN = 0, + GENERATOR_YIELD = 1, + } generator_return_kind; + /* Head of circular linked-list of all tasks which are instances of `asyncio.Task` or subclasses of it used in `asyncio.all_tasks`. */ diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 6130e5cad21bf4..a11959fb4057df 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -535,572 +535,574 @@ extern "C" { #define _FORMAT_SIMPLE_r11 728 #define _FORMAT_WITH_SPEC_r21 729 #define _FOR_ITER_r23 730 -#define _FOR_ITER_GEN_FRAME_r23 731 -#define _FOR_ITER_TIER_TWO_r23 732 -#define _GET_AITER_r11 733 -#define _GET_ANEXT_r12 734 -#define _GET_AWAITABLE_r11 735 -#define _GET_ITER_r12 736 -#define _GET_LEN_r12 737 -#define _GET_YIELD_FROM_ITER_r11 738 -#define _GUARD_BINARY_OP_EXTEND_r22 739 -#define _GUARD_CALLABLE_ISINSTANCE_r03 740 -#define _GUARD_CALLABLE_ISINSTANCE_r13 741 -#define _GUARD_CALLABLE_ISINSTANCE_r23 742 -#define _GUARD_CALLABLE_ISINSTANCE_r33 743 -#define _GUARD_CALLABLE_LEN_r03 744 -#define _GUARD_CALLABLE_LEN_r13 745 -#define _GUARD_CALLABLE_LEN_r23 746 -#define _GUARD_CALLABLE_LEN_r33 747 -#define _GUARD_CALLABLE_LIST_APPEND_r03 748 -#define _GUARD_CALLABLE_LIST_APPEND_r13 749 -#define _GUARD_CALLABLE_LIST_APPEND_r23 750 -#define _GUARD_CALLABLE_LIST_APPEND_r33 751 -#define _GUARD_CALLABLE_STR_1_r03 752 -#define _GUARD_CALLABLE_STR_1_r13 753 -#define _GUARD_CALLABLE_STR_1_r23 754 -#define _GUARD_CALLABLE_STR_1_r33 755 -#define _GUARD_CALLABLE_TUPLE_1_r03 756 -#define _GUARD_CALLABLE_TUPLE_1_r13 757 -#define _GUARD_CALLABLE_TUPLE_1_r23 758 -#define _GUARD_CALLABLE_TUPLE_1_r33 759 -#define _GUARD_CALLABLE_TYPE_1_r03 760 -#define _GUARD_CALLABLE_TYPE_1_r13 761 -#define _GUARD_CALLABLE_TYPE_1_r23 762 -#define _GUARD_CALLABLE_TYPE_1_r33 763 -#define _GUARD_DORV_NO_DICT_r01 764 -#define _GUARD_DORV_NO_DICT_r11 765 -#define _GUARD_DORV_NO_DICT_r22 766 -#define _GUARD_DORV_NO_DICT_r33 767 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 768 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 769 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 770 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 771 -#define _GUARD_GLOBALS_VERSION_r00 772 -#define _GUARD_GLOBALS_VERSION_r11 773 -#define _GUARD_GLOBALS_VERSION_r22 774 -#define _GUARD_GLOBALS_VERSION_r33 775 -#define _GUARD_IP_RETURN_GENERATOR_r00 776 -#define _GUARD_IP_RETURN_GENERATOR_r11 777 -#define _GUARD_IP_RETURN_GENERATOR_r22 778 -#define _GUARD_IP_RETURN_GENERATOR_r33 779 -#define _GUARD_IP_RETURN_VALUE_r00 780 -#define _GUARD_IP_RETURN_VALUE_r11 781 -#define _GUARD_IP_RETURN_VALUE_r22 782 -#define _GUARD_IP_RETURN_VALUE_r33 783 -#define _GUARD_IP_YIELD_VALUE_r00 784 -#define _GUARD_IP_YIELD_VALUE_r11 785 -#define _GUARD_IP_YIELD_VALUE_r22 786 -#define _GUARD_IP_YIELD_VALUE_r33 787 -#define _GUARD_IP__PUSH_FRAME_r00 788 -#define _GUARD_IP__PUSH_FRAME_r11 789 -#define _GUARD_IP__PUSH_FRAME_r22 790 -#define _GUARD_IP__PUSH_FRAME_r33 791 -#define _GUARD_IS_FALSE_POP_r00 792 -#define _GUARD_IS_FALSE_POP_r10 793 -#define _GUARD_IS_FALSE_POP_r21 794 -#define _GUARD_IS_FALSE_POP_r32 795 -#define _GUARD_IS_NONE_POP_r00 796 -#define _GUARD_IS_NONE_POP_r10 797 -#define _GUARD_IS_NONE_POP_r21 798 -#define _GUARD_IS_NONE_POP_r32 799 -#define _GUARD_IS_NOT_NONE_POP_r10 800 -#define _GUARD_IS_TRUE_POP_r00 801 -#define _GUARD_IS_TRUE_POP_r10 802 -#define _GUARD_IS_TRUE_POP_r21 803 -#define _GUARD_IS_TRUE_POP_r32 804 -#define _GUARD_KEYS_VERSION_r01 805 -#define _GUARD_KEYS_VERSION_r11 806 -#define _GUARD_KEYS_VERSION_r22 807 -#define _GUARD_KEYS_VERSION_r33 808 -#define _GUARD_NOS_DICT_r02 809 -#define _GUARD_NOS_DICT_r12 810 -#define _GUARD_NOS_DICT_r22 811 -#define _GUARD_NOS_DICT_r33 812 -#define _GUARD_NOS_FLOAT_r02 813 -#define _GUARD_NOS_FLOAT_r12 814 -#define _GUARD_NOS_FLOAT_r22 815 -#define _GUARD_NOS_FLOAT_r33 816 -#define _GUARD_NOS_INT_r02 817 -#define _GUARD_NOS_INT_r12 818 -#define _GUARD_NOS_INT_r22 819 -#define _GUARD_NOS_INT_r33 820 -#define _GUARD_NOS_LIST_r02 821 -#define _GUARD_NOS_LIST_r12 822 -#define _GUARD_NOS_LIST_r22 823 -#define _GUARD_NOS_LIST_r33 824 -#define _GUARD_NOS_NOT_NULL_r02 825 -#define _GUARD_NOS_NOT_NULL_r12 826 -#define _GUARD_NOS_NOT_NULL_r22 827 -#define _GUARD_NOS_NOT_NULL_r33 828 -#define _GUARD_NOS_NULL_r02 829 -#define _GUARD_NOS_NULL_r12 830 -#define _GUARD_NOS_NULL_r22 831 -#define _GUARD_NOS_NULL_r33 832 -#define _GUARD_NOS_OVERFLOWED_r02 833 -#define _GUARD_NOS_OVERFLOWED_r12 834 -#define _GUARD_NOS_OVERFLOWED_r22 835 -#define _GUARD_NOS_OVERFLOWED_r33 836 -#define _GUARD_NOS_TUPLE_r02 837 -#define _GUARD_NOS_TUPLE_r12 838 -#define _GUARD_NOS_TUPLE_r22 839 -#define _GUARD_NOS_TUPLE_r33 840 -#define _GUARD_NOS_UNICODE_r02 841 -#define _GUARD_NOS_UNICODE_r12 842 -#define _GUARD_NOS_UNICODE_r22 843 -#define _GUARD_NOS_UNICODE_r33 844 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 845 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 846 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 847 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 848 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 849 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 850 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 851 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 852 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 853 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 854 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 855 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 856 -#define _GUARD_THIRD_NULL_r03 857 -#define _GUARD_THIRD_NULL_r13 858 -#define _GUARD_THIRD_NULL_r23 859 -#define _GUARD_THIRD_NULL_r33 860 -#define _GUARD_TOS_ANY_SET_r01 861 -#define _GUARD_TOS_ANY_SET_r11 862 -#define _GUARD_TOS_ANY_SET_r22 863 -#define _GUARD_TOS_ANY_SET_r33 864 -#define _GUARD_TOS_DICT_r01 865 -#define _GUARD_TOS_DICT_r11 866 -#define _GUARD_TOS_DICT_r22 867 -#define _GUARD_TOS_DICT_r33 868 -#define _GUARD_TOS_FLOAT_r01 869 -#define _GUARD_TOS_FLOAT_r11 870 -#define _GUARD_TOS_FLOAT_r22 871 -#define _GUARD_TOS_FLOAT_r33 872 -#define _GUARD_TOS_INT_r01 873 -#define _GUARD_TOS_INT_r11 874 -#define _GUARD_TOS_INT_r22 875 -#define _GUARD_TOS_INT_r33 876 -#define _GUARD_TOS_LIST_r01 877 -#define _GUARD_TOS_LIST_r11 878 -#define _GUARD_TOS_LIST_r22 879 -#define _GUARD_TOS_LIST_r33 880 -#define _GUARD_TOS_OVERFLOWED_r01 881 -#define _GUARD_TOS_OVERFLOWED_r11 882 -#define _GUARD_TOS_OVERFLOWED_r22 883 -#define _GUARD_TOS_OVERFLOWED_r33 884 -#define _GUARD_TOS_SLICE_r01 885 -#define _GUARD_TOS_SLICE_r11 886 -#define _GUARD_TOS_SLICE_r22 887 -#define _GUARD_TOS_SLICE_r33 888 -#define _GUARD_TOS_TUPLE_r01 889 -#define _GUARD_TOS_TUPLE_r11 890 -#define _GUARD_TOS_TUPLE_r22 891 -#define _GUARD_TOS_TUPLE_r33 892 -#define _GUARD_TOS_UNICODE_r01 893 -#define _GUARD_TOS_UNICODE_r11 894 -#define _GUARD_TOS_UNICODE_r22 895 -#define _GUARD_TOS_UNICODE_r33 896 -#define _GUARD_TYPE_VERSION_r01 897 -#define _GUARD_TYPE_VERSION_r11 898 -#define _GUARD_TYPE_VERSION_r22 899 -#define _GUARD_TYPE_VERSION_r33 900 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 901 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 902 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 903 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 904 -#define _HANDLE_PENDING_AND_DEOPT_r00 905 -#define _HANDLE_PENDING_AND_DEOPT_r10 906 -#define _HANDLE_PENDING_AND_DEOPT_r20 907 -#define _HANDLE_PENDING_AND_DEOPT_r30 908 -#define _IMPORT_FROM_r12 909 -#define _IMPORT_NAME_r21 910 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 911 -#define _INIT_CALL_PY_EXACT_ARGS_r01 912 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 913 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 914 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 915 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 916 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 917 -#define _INSERT_NULL_r10 918 -#define _INSTRUMENTED_FOR_ITER_r23 919 -#define _INSTRUMENTED_INSTRUCTION_r00 920 -#define _INSTRUMENTED_JUMP_FORWARD_r00 921 -#define _INSTRUMENTED_JUMP_FORWARD_r11 922 -#define _INSTRUMENTED_JUMP_FORWARD_r22 923 -#define _INSTRUMENTED_JUMP_FORWARD_r33 924 -#define _INSTRUMENTED_LINE_r00 925 -#define _INSTRUMENTED_NOT_TAKEN_r00 926 -#define _INSTRUMENTED_NOT_TAKEN_r11 927 -#define _INSTRUMENTED_NOT_TAKEN_r22 928 -#define _INSTRUMENTED_NOT_TAKEN_r33 929 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 930 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 931 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 932 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 933 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 934 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 935 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 936 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 937 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 938 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 939 -#define _IS_NONE_r11 940 -#define _IS_OP_r21 941 -#define _ITER_CHECK_LIST_r02 942 -#define _ITER_CHECK_LIST_r12 943 -#define _ITER_CHECK_LIST_r22 944 -#define _ITER_CHECK_LIST_r33 945 -#define _ITER_CHECK_RANGE_r02 946 -#define _ITER_CHECK_RANGE_r12 947 -#define _ITER_CHECK_RANGE_r22 948 -#define _ITER_CHECK_RANGE_r33 949 -#define _ITER_CHECK_TUPLE_r02 950 -#define _ITER_CHECK_TUPLE_r12 951 -#define _ITER_CHECK_TUPLE_r22 952 -#define _ITER_CHECK_TUPLE_r33 953 -#define _ITER_JUMP_LIST_r02 954 -#define _ITER_JUMP_LIST_r12 955 -#define _ITER_JUMP_LIST_r22 956 -#define _ITER_JUMP_LIST_r33 957 -#define _ITER_JUMP_RANGE_r02 958 -#define _ITER_JUMP_RANGE_r12 959 -#define _ITER_JUMP_RANGE_r22 960 -#define _ITER_JUMP_RANGE_r33 961 -#define _ITER_JUMP_TUPLE_r02 962 -#define _ITER_JUMP_TUPLE_r12 963 -#define _ITER_JUMP_TUPLE_r22 964 -#define _ITER_JUMP_TUPLE_r33 965 -#define _ITER_NEXT_LIST_r23 966 -#define _ITER_NEXT_LIST_TIER_TWO_r23 967 -#define _ITER_NEXT_RANGE_r03 968 -#define _ITER_NEXT_RANGE_r13 969 -#define _ITER_NEXT_RANGE_r23 970 -#define _ITER_NEXT_TUPLE_r03 971 -#define _ITER_NEXT_TUPLE_r13 972 -#define _ITER_NEXT_TUPLE_r23 973 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 974 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 975 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 976 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 977 -#define _JUMP_TO_TOP_r00 978 -#define _LIST_APPEND_r10 979 -#define _LIST_EXTEND_r10 980 -#define _LOAD_ATTR_r10 981 -#define _LOAD_ATTR_CLASS_r11 982 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 983 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 984 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 985 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 986 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 987 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 988 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 989 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 990 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 991 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 992 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 993 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 994 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 995 -#define _LOAD_ATTR_MODULE_r11 996 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 997 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 998 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 999 -#define _LOAD_ATTR_SLOT_r11 1000 -#define _LOAD_ATTR_WITH_HINT_r11 1001 -#define _LOAD_BUILD_CLASS_r01 1002 -#define _LOAD_BYTECODE_r00 1003 -#define _LOAD_COMMON_CONSTANT_r01 1004 -#define _LOAD_COMMON_CONSTANT_r12 1005 -#define _LOAD_COMMON_CONSTANT_r23 1006 -#define _LOAD_CONST_r01 1007 -#define _LOAD_CONST_r12 1008 -#define _LOAD_CONST_r23 1009 -#define _LOAD_CONST_INLINE_r01 1010 -#define _LOAD_CONST_INLINE_r12 1011 -#define _LOAD_CONST_INLINE_r23 1012 -#define _LOAD_CONST_INLINE_BORROW_r01 1013 -#define _LOAD_CONST_INLINE_BORROW_r12 1014 -#define _LOAD_CONST_INLINE_BORROW_r23 1015 -#define _LOAD_CONST_UNDER_INLINE_r02 1016 -#define _LOAD_CONST_UNDER_INLINE_r12 1017 -#define _LOAD_CONST_UNDER_INLINE_r23 1018 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1019 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1020 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1021 -#define _LOAD_DEREF_r01 1022 -#define _LOAD_FAST_r01 1023 -#define _LOAD_FAST_r12 1024 -#define _LOAD_FAST_r23 1025 -#define _LOAD_FAST_0_r01 1026 -#define _LOAD_FAST_0_r12 1027 -#define _LOAD_FAST_0_r23 1028 -#define _LOAD_FAST_1_r01 1029 -#define _LOAD_FAST_1_r12 1030 -#define _LOAD_FAST_1_r23 1031 -#define _LOAD_FAST_2_r01 1032 -#define _LOAD_FAST_2_r12 1033 -#define _LOAD_FAST_2_r23 1034 -#define _LOAD_FAST_3_r01 1035 -#define _LOAD_FAST_3_r12 1036 -#define _LOAD_FAST_3_r23 1037 -#define _LOAD_FAST_4_r01 1038 -#define _LOAD_FAST_4_r12 1039 -#define _LOAD_FAST_4_r23 1040 -#define _LOAD_FAST_5_r01 1041 -#define _LOAD_FAST_5_r12 1042 -#define _LOAD_FAST_5_r23 1043 -#define _LOAD_FAST_6_r01 1044 -#define _LOAD_FAST_6_r12 1045 -#define _LOAD_FAST_6_r23 1046 -#define _LOAD_FAST_7_r01 1047 -#define _LOAD_FAST_7_r12 1048 -#define _LOAD_FAST_7_r23 1049 -#define _LOAD_FAST_AND_CLEAR_r01 1050 -#define _LOAD_FAST_AND_CLEAR_r12 1051 -#define _LOAD_FAST_AND_CLEAR_r23 1052 -#define _LOAD_FAST_BORROW_r01 1053 -#define _LOAD_FAST_BORROW_r12 1054 -#define _LOAD_FAST_BORROW_r23 1055 -#define _LOAD_FAST_BORROW_0_r01 1056 -#define _LOAD_FAST_BORROW_0_r12 1057 -#define _LOAD_FAST_BORROW_0_r23 1058 -#define _LOAD_FAST_BORROW_1_r01 1059 -#define _LOAD_FAST_BORROW_1_r12 1060 -#define _LOAD_FAST_BORROW_1_r23 1061 -#define _LOAD_FAST_BORROW_2_r01 1062 -#define _LOAD_FAST_BORROW_2_r12 1063 -#define _LOAD_FAST_BORROW_2_r23 1064 -#define _LOAD_FAST_BORROW_3_r01 1065 -#define _LOAD_FAST_BORROW_3_r12 1066 -#define _LOAD_FAST_BORROW_3_r23 1067 -#define _LOAD_FAST_BORROW_4_r01 1068 -#define _LOAD_FAST_BORROW_4_r12 1069 -#define _LOAD_FAST_BORROW_4_r23 1070 -#define _LOAD_FAST_BORROW_5_r01 1071 -#define _LOAD_FAST_BORROW_5_r12 1072 -#define _LOAD_FAST_BORROW_5_r23 1073 -#define _LOAD_FAST_BORROW_6_r01 1074 -#define _LOAD_FAST_BORROW_6_r12 1075 -#define _LOAD_FAST_BORROW_6_r23 1076 -#define _LOAD_FAST_BORROW_7_r01 1077 -#define _LOAD_FAST_BORROW_7_r12 1078 -#define _LOAD_FAST_BORROW_7_r23 1079 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1080 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1081 -#define _LOAD_FAST_CHECK_r01 1082 -#define _LOAD_FAST_CHECK_r12 1083 -#define _LOAD_FAST_CHECK_r23 1084 -#define _LOAD_FAST_LOAD_FAST_r02 1085 -#define _LOAD_FAST_LOAD_FAST_r13 1086 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1087 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1088 -#define _LOAD_GLOBAL_r00 1089 -#define _LOAD_GLOBAL_BUILTINS_r01 1090 -#define _LOAD_GLOBAL_MODULE_r01 1091 -#define _LOAD_LOCALS_r01 1092 -#define _LOAD_LOCALS_r12 1093 -#define _LOAD_LOCALS_r23 1094 -#define _LOAD_NAME_r01 1095 -#define _LOAD_SMALL_INT_r01 1096 -#define _LOAD_SMALL_INT_r12 1097 -#define _LOAD_SMALL_INT_r23 1098 -#define _LOAD_SMALL_INT_0_r01 1099 -#define _LOAD_SMALL_INT_0_r12 1100 -#define _LOAD_SMALL_INT_0_r23 1101 -#define _LOAD_SMALL_INT_1_r01 1102 -#define _LOAD_SMALL_INT_1_r12 1103 -#define _LOAD_SMALL_INT_1_r23 1104 -#define _LOAD_SMALL_INT_2_r01 1105 -#define _LOAD_SMALL_INT_2_r12 1106 -#define _LOAD_SMALL_INT_2_r23 1107 -#define _LOAD_SMALL_INT_3_r01 1108 -#define _LOAD_SMALL_INT_3_r12 1109 -#define _LOAD_SMALL_INT_3_r23 1110 -#define _LOAD_SPECIAL_r00 1111 -#define _LOAD_SUPER_ATTR_ATTR_r31 1112 -#define _LOAD_SUPER_ATTR_METHOD_r32 1113 -#define _MAKE_CALLARGS_A_TUPLE_r33 1114 -#define _MAKE_CELL_r00 1115 -#define _MAKE_FUNCTION_r11 1116 -#define _MAKE_WARM_r00 1117 -#define _MAKE_WARM_r11 1118 -#define _MAKE_WARM_r22 1119 -#define _MAKE_WARM_r33 1120 -#define _MAP_ADD_r20 1121 -#define _MATCH_CLASS_r31 1122 -#define _MATCH_KEYS_r23 1123 -#define _MATCH_MAPPING_r02 1124 -#define _MATCH_MAPPING_r12 1125 -#define _MATCH_MAPPING_r23 1126 -#define _MATCH_SEQUENCE_r02 1127 -#define _MATCH_SEQUENCE_r12 1128 -#define _MATCH_SEQUENCE_r23 1129 -#define _MAYBE_EXPAND_METHOD_r00 1130 -#define _MAYBE_EXPAND_METHOD_KW_r11 1131 -#define _MONITOR_CALL_r00 1132 -#define _MONITOR_CALL_KW_r11 1133 -#define _MONITOR_JUMP_BACKWARD_r00 1134 -#define _MONITOR_JUMP_BACKWARD_r11 1135 -#define _MONITOR_JUMP_BACKWARD_r22 1136 -#define _MONITOR_JUMP_BACKWARD_r33 1137 -#define _MONITOR_RESUME_r00 1138 -#define _NOP_r00 1139 -#define _NOP_r11 1140 -#define _NOP_r22 1141 -#define _NOP_r33 1142 -#define _POP_CALL_r20 1143 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1144 -#define _POP_CALL_ONE_r30 1145 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1146 -#define _POP_CALL_TWO_r30 1147 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1148 -#define _POP_EXCEPT_r10 1149 -#define _POP_ITER_r20 1150 -#define _POP_JUMP_IF_FALSE_r00 1151 -#define _POP_JUMP_IF_FALSE_r10 1152 -#define _POP_JUMP_IF_FALSE_r21 1153 -#define _POP_JUMP_IF_FALSE_r32 1154 -#define _POP_JUMP_IF_TRUE_r00 1155 -#define _POP_JUMP_IF_TRUE_r10 1156 -#define _POP_JUMP_IF_TRUE_r21 1157 -#define _POP_JUMP_IF_TRUE_r32 1158 -#define _POP_TOP_r10 1159 -#define _POP_TOP_FLOAT_r00 1160 -#define _POP_TOP_FLOAT_r10 1161 -#define _POP_TOP_FLOAT_r21 1162 -#define _POP_TOP_FLOAT_r32 1163 -#define _POP_TOP_INT_r00 1164 -#define _POP_TOP_INT_r10 1165 -#define _POP_TOP_INT_r21 1166 -#define _POP_TOP_INT_r32 1167 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1168 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1169 -#define _POP_TOP_NOP_r00 1170 -#define _POP_TOP_NOP_r10 1171 -#define _POP_TOP_NOP_r21 1172 -#define _POP_TOP_NOP_r32 1173 -#define _POP_TOP_UNICODE_r00 1174 -#define _POP_TOP_UNICODE_r10 1175 -#define _POP_TOP_UNICODE_r21 1176 -#define _POP_TOP_UNICODE_r32 1177 -#define _POP_TWO_r20 1178 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1179 -#define _PUSH_EXC_INFO_r02 1180 -#define _PUSH_EXC_INFO_r12 1181 -#define _PUSH_EXC_INFO_r23 1182 -#define _PUSH_FRAME_r10 1183 -#define _PUSH_NULL_r01 1184 -#define _PUSH_NULL_r12 1185 -#define _PUSH_NULL_r23 1186 -#define _PUSH_NULL_CONDITIONAL_r00 1187 -#define _PY_FRAME_GENERAL_r01 1188 -#define _PY_FRAME_KW_r11 1189 -#define _QUICKEN_RESUME_r00 1190 -#define _QUICKEN_RESUME_r11 1191 -#define _QUICKEN_RESUME_r22 1192 -#define _QUICKEN_RESUME_r33 1193 -#define _REPLACE_WITH_TRUE_r11 1194 -#define _RESUME_CHECK_r00 1195 -#define _RESUME_CHECK_r11 1196 -#define _RESUME_CHECK_r22 1197 -#define _RESUME_CHECK_r33 1198 -#define _RETURN_GENERATOR_r01 1199 -#define _RETURN_VALUE_r11 1200 -#define _SAVE_RETURN_OFFSET_r00 1201 -#define _SAVE_RETURN_OFFSET_r11 1202 -#define _SAVE_RETURN_OFFSET_r22 1203 -#define _SAVE_RETURN_OFFSET_r33 1204 -#define _SEND_r22 1205 -#define _SEND_GEN_FRAME_r22 1206 -#define _SETUP_ANNOTATIONS_r00 1207 -#define _SET_ADD_r10 1208 -#define _SET_FUNCTION_ATTRIBUTE_r01 1209 -#define _SET_FUNCTION_ATTRIBUTE_r11 1210 -#define _SET_FUNCTION_ATTRIBUTE_r21 1211 -#define _SET_FUNCTION_ATTRIBUTE_r32 1212 -#define _SET_IP_r00 1213 -#define _SET_IP_r11 1214 -#define _SET_IP_r22 1215 -#define _SET_IP_r33 1216 -#define _SET_UPDATE_r10 1217 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1218 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1219 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1220 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1221 -#define _SPILL_OR_RELOAD_r01 1222 -#define _SPILL_OR_RELOAD_r02 1223 -#define _SPILL_OR_RELOAD_r03 1224 -#define _SPILL_OR_RELOAD_r10 1225 -#define _SPILL_OR_RELOAD_r12 1226 -#define _SPILL_OR_RELOAD_r13 1227 -#define _SPILL_OR_RELOAD_r20 1228 -#define _SPILL_OR_RELOAD_r21 1229 -#define _SPILL_OR_RELOAD_r23 1230 -#define _SPILL_OR_RELOAD_r30 1231 -#define _SPILL_OR_RELOAD_r31 1232 -#define _SPILL_OR_RELOAD_r32 1233 -#define _START_EXECUTOR_r00 1234 -#define _STORE_ATTR_r20 1235 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1236 -#define _STORE_ATTR_SLOT_r21 1237 -#define _STORE_ATTR_WITH_HINT_r21 1238 -#define _STORE_DEREF_r10 1239 -#define _STORE_FAST_r10 1240 -#define _STORE_FAST_0_r10 1241 -#define _STORE_FAST_1_r10 1242 -#define _STORE_FAST_2_r10 1243 -#define _STORE_FAST_3_r10 1244 -#define _STORE_FAST_4_r10 1245 -#define _STORE_FAST_5_r10 1246 -#define _STORE_FAST_6_r10 1247 -#define _STORE_FAST_7_r10 1248 -#define _STORE_FAST_LOAD_FAST_r11 1249 -#define _STORE_FAST_STORE_FAST_r20 1250 -#define _STORE_GLOBAL_r10 1251 -#define _STORE_NAME_r10 1252 -#define _STORE_SLICE_r30 1253 -#define _STORE_SUBSCR_r30 1254 -#define _STORE_SUBSCR_DICT_r31 1255 -#define _STORE_SUBSCR_LIST_INT_r32 1256 -#define _SWAP_r11 1257 -#define _SWAP_2_r02 1258 -#define _SWAP_2_r12 1259 -#define _SWAP_2_r22 1260 -#define _SWAP_2_r33 1261 -#define _SWAP_3_r03 1262 -#define _SWAP_3_r13 1263 -#define _SWAP_3_r23 1264 -#define _SWAP_3_r33 1265 -#define _TIER2_RESUME_CHECK_r00 1266 -#define _TIER2_RESUME_CHECK_r11 1267 -#define _TIER2_RESUME_CHECK_r22 1268 -#define _TIER2_RESUME_CHECK_r33 1269 -#define _TO_BOOL_r11 1270 -#define _TO_BOOL_BOOL_r01 1271 -#define _TO_BOOL_BOOL_r11 1272 -#define _TO_BOOL_BOOL_r22 1273 -#define _TO_BOOL_BOOL_r33 1274 -#define _TO_BOOL_INT_r11 1275 -#define _TO_BOOL_LIST_r11 1276 -#define _TO_BOOL_NONE_r01 1277 -#define _TO_BOOL_NONE_r11 1278 -#define _TO_BOOL_NONE_r22 1279 -#define _TO_BOOL_NONE_r33 1280 -#define _TO_BOOL_STR_r11 1281 -#define _TRACE_RECORD_r00 1282 -#define _UNARY_INVERT_r11 1283 -#define _UNARY_NEGATIVE_r11 1284 -#define _UNARY_NOT_r01 1285 -#define _UNARY_NOT_r11 1286 -#define _UNARY_NOT_r22 1287 -#define _UNARY_NOT_r33 1288 -#define _UNPACK_EX_r10 1289 -#define _UNPACK_SEQUENCE_r10 1290 -#define _UNPACK_SEQUENCE_LIST_r10 1291 -#define _UNPACK_SEQUENCE_TUPLE_r10 1292 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1293 -#define _WITH_EXCEPT_START_r33 1294 -#define _YIELD_VALUE_r11 1295 -#define MAX_UOP_REGS_ID 1295 +#define _FOR_ITER_GEN_FRAME_r03 731 +#define _FOR_ITER_GEN_FRAME_r13 732 +#define _FOR_ITER_GEN_FRAME_r23 733 +#define _FOR_ITER_TIER_TWO_r23 734 +#define _GET_AITER_r11 735 +#define _GET_ANEXT_r12 736 +#define _GET_AWAITABLE_r11 737 +#define _GET_ITER_r12 738 +#define _GET_LEN_r12 739 +#define _GET_YIELD_FROM_ITER_r11 740 +#define _GUARD_BINARY_OP_EXTEND_r22 741 +#define _GUARD_CALLABLE_ISINSTANCE_r03 742 +#define _GUARD_CALLABLE_ISINSTANCE_r13 743 +#define _GUARD_CALLABLE_ISINSTANCE_r23 744 +#define _GUARD_CALLABLE_ISINSTANCE_r33 745 +#define _GUARD_CALLABLE_LEN_r03 746 +#define _GUARD_CALLABLE_LEN_r13 747 +#define _GUARD_CALLABLE_LEN_r23 748 +#define _GUARD_CALLABLE_LEN_r33 749 +#define _GUARD_CALLABLE_LIST_APPEND_r03 750 +#define _GUARD_CALLABLE_LIST_APPEND_r13 751 +#define _GUARD_CALLABLE_LIST_APPEND_r23 752 +#define _GUARD_CALLABLE_LIST_APPEND_r33 753 +#define _GUARD_CALLABLE_STR_1_r03 754 +#define _GUARD_CALLABLE_STR_1_r13 755 +#define _GUARD_CALLABLE_STR_1_r23 756 +#define _GUARD_CALLABLE_STR_1_r33 757 +#define _GUARD_CALLABLE_TUPLE_1_r03 758 +#define _GUARD_CALLABLE_TUPLE_1_r13 759 +#define _GUARD_CALLABLE_TUPLE_1_r23 760 +#define _GUARD_CALLABLE_TUPLE_1_r33 761 +#define _GUARD_CALLABLE_TYPE_1_r03 762 +#define _GUARD_CALLABLE_TYPE_1_r13 763 +#define _GUARD_CALLABLE_TYPE_1_r23 764 +#define _GUARD_CALLABLE_TYPE_1_r33 765 +#define _GUARD_DORV_NO_DICT_r01 766 +#define _GUARD_DORV_NO_DICT_r11 767 +#define _GUARD_DORV_NO_DICT_r22 768 +#define _GUARD_DORV_NO_DICT_r33 769 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 770 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 771 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 772 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 773 +#define _GUARD_GLOBALS_VERSION_r00 774 +#define _GUARD_GLOBALS_VERSION_r11 775 +#define _GUARD_GLOBALS_VERSION_r22 776 +#define _GUARD_GLOBALS_VERSION_r33 777 +#define _GUARD_IP_RETURN_GENERATOR_r00 778 +#define _GUARD_IP_RETURN_GENERATOR_r11 779 +#define _GUARD_IP_RETURN_GENERATOR_r22 780 +#define _GUARD_IP_RETURN_GENERATOR_r33 781 +#define _GUARD_IP_RETURN_VALUE_r00 782 +#define _GUARD_IP_RETURN_VALUE_r11 783 +#define _GUARD_IP_RETURN_VALUE_r22 784 +#define _GUARD_IP_RETURN_VALUE_r33 785 +#define _GUARD_IP_YIELD_VALUE_r00 786 +#define _GUARD_IP_YIELD_VALUE_r11 787 +#define _GUARD_IP_YIELD_VALUE_r22 788 +#define _GUARD_IP_YIELD_VALUE_r33 789 +#define _GUARD_IP__PUSH_FRAME_r00 790 +#define _GUARD_IP__PUSH_FRAME_r11 791 +#define _GUARD_IP__PUSH_FRAME_r22 792 +#define _GUARD_IP__PUSH_FRAME_r33 793 +#define _GUARD_IS_FALSE_POP_r00 794 +#define _GUARD_IS_FALSE_POP_r10 795 +#define _GUARD_IS_FALSE_POP_r21 796 +#define _GUARD_IS_FALSE_POP_r32 797 +#define _GUARD_IS_NONE_POP_r00 798 +#define _GUARD_IS_NONE_POP_r10 799 +#define _GUARD_IS_NONE_POP_r21 800 +#define _GUARD_IS_NONE_POP_r32 801 +#define _GUARD_IS_NOT_NONE_POP_r10 802 +#define _GUARD_IS_TRUE_POP_r00 803 +#define _GUARD_IS_TRUE_POP_r10 804 +#define _GUARD_IS_TRUE_POP_r21 805 +#define _GUARD_IS_TRUE_POP_r32 806 +#define _GUARD_KEYS_VERSION_r01 807 +#define _GUARD_KEYS_VERSION_r11 808 +#define _GUARD_KEYS_VERSION_r22 809 +#define _GUARD_KEYS_VERSION_r33 810 +#define _GUARD_NOS_DICT_r02 811 +#define _GUARD_NOS_DICT_r12 812 +#define _GUARD_NOS_DICT_r22 813 +#define _GUARD_NOS_DICT_r33 814 +#define _GUARD_NOS_FLOAT_r02 815 +#define _GUARD_NOS_FLOAT_r12 816 +#define _GUARD_NOS_FLOAT_r22 817 +#define _GUARD_NOS_FLOAT_r33 818 +#define _GUARD_NOS_INT_r02 819 +#define _GUARD_NOS_INT_r12 820 +#define _GUARD_NOS_INT_r22 821 +#define _GUARD_NOS_INT_r33 822 +#define _GUARD_NOS_LIST_r02 823 +#define _GUARD_NOS_LIST_r12 824 +#define _GUARD_NOS_LIST_r22 825 +#define _GUARD_NOS_LIST_r33 826 +#define _GUARD_NOS_NOT_NULL_r02 827 +#define _GUARD_NOS_NOT_NULL_r12 828 +#define _GUARD_NOS_NOT_NULL_r22 829 +#define _GUARD_NOS_NOT_NULL_r33 830 +#define _GUARD_NOS_NULL_r02 831 +#define _GUARD_NOS_NULL_r12 832 +#define _GUARD_NOS_NULL_r22 833 +#define _GUARD_NOS_NULL_r33 834 +#define _GUARD_NOS_OVERFLOWED_r02 835 +#define _GUARD_NOS_OVERFLOWED_r12 836 +#define _GUARD_NOS_OVERFLOWED_r22 837 +#define _GUARD_NOS_OVERFLOWED_r33 838 +#define _GUARD_NOS_TUPLE_r02 839 +#define _GUARD_NOS_TUPLE_r12 840 +#define _GUARD_NOS_TUPLE_r22 841 +#define _GUARD_NOS_TUPLE_r33 842 +#define _GUARD_NOS_UNICODE_r02 843 +#define _GUARD_NOS_UNICODE_r12 844 +#define _GUARD_NOS_UNICODE_r22 845 +#define _GUARD_NOS_UNICODE_r33 846 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 847 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 848 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 849 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 850 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 851 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 852 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 853 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 854 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 855 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 856 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 857 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 858 +#define _GUARD_THIRD_NULL_r03 859 +#define _GUARD_THIRD_NULL_r13 860 +#define _GUARD_THIRD_NULL_r23 861 +#define _GUARD_THIRD_NULL_r33 862 +#define _GUARD_TOS_ANY_SET_r01 863 +#define _GUARD_TOS_ANY_SET_r11 864 +#define _GUARD_TOS_ANY_SET_r22 865 +#define _GUARD_TOS_ANY_SET_r33 866 +#define _GUARD_TOS_DICT_r01 867 +#define _GUARD_TOS_DICT_r11 868 +#define _GUARD_TOS_DICT_r22 869 +#define _GUARD_TOS_DICT_r33 870 +#define _GUARD_TOS_FLOAT_r01 871 +#define _GUARD_TOS_FLOAT_r11 872 +#define _GUARD_TOS_FLOAT_r22 873 +#define _GUARD_TOS_FLOAT_r33 874 +#define _GUARD_TOS_INT_r01 875 +#define _GUARD_TOS_INT_r11 876 +#define _GUARD_TOS_INT_r22 877 +#define _GUARD_TOS_INT_r33 878 +#define _GUARD_TOS_LIST_r01 879 +#define _GUARD_TOS_LIST_r11 880 +#define _GUARD_TOS_LIST_r22 881 +#define _GUARD_TOS_LIST_r33 882 +#define _GUARD_TOS_OVERFLOWED_r01 883 +#define _GUARD_TOS_OVERFLOWED_r11 884 +#define _GUARD_TOS_OVERFLOWED_r22 885 +#define _GUARD_TOS_OVERFLOWED_r33 886 +#define _GUARD_TOS_SLICE_r01 887 +#define _GUARD_TOS_SLICE_r11 888 +#define _GUARD_TOS_SLICE_r22 889 +#define _GUARD_TOS_SLICE_r33 890 +#define _GUARD_TOS_TUPLE_r01 891 +#define _GUARD_TOS_TUPLE_r11 892 +#define _GUARD_TOS_TUPLE_r22 893 +#define _GUARD_TOS_TUPLE_r33 894 +#define _GUARD_TOS_UNICODE_r01 895 +#define _GUARD_TOS_UNICODE_r11 896 +#define _GUARD_TOS_UNICODE_r22 897 +#define _GUARD_TOS_UNICODE_r33 898 +#define _GUARD_TYPE_VERSION_r01 899 +#define _GUARD_TYPE_VERSION_r11 900 +#define _GUARD_TYPE_VERSION_r22 901 +#define _GUARD_TYPE_VERSION_r33 902 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 903 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 904 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 905 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 906 +#define _HANDLE_PENDING_AND_DEOPT_r00 907 +#define _HANDLE_PENDING_AND_DEOPT_r10 908 +#define _HANDLE_PENDING_AND_DEOPT_r20 909 +#define _HANDLE_PENDING_AND_DEOPT_r30 910 +#define _IMPORT_FROM_r12 911 +#define _IMPORT_NAME_r21 912 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 913 +#define _INIT_CALL_PY_EXACT_ARGS_r01 914 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 915 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 916 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 917 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 918 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 919 +#define _INSERT_NULL_r10 920 +#define _INSTRUMENTED_FOR_ITER_r23 921 +#define _INSTRUMENTED_INSTRUCTION_r00 922 +#define _INSTRUMENTED_JUMP_FORWARD_r00 923 +#define _INSTRUMENTED_JUMP_FORWARD_r11 924 +#define _INSTRUMENTED_JUMP_FORWARD_r22 925 +#define _INSTRUMENTED_JUMP_FORWARD_r33 926 +#define _INSTRUMENTED_LINE_r00 927 +#define _INSTRUMENTED_NOT_TAKEN_r00 928 +#define _INSTRUMENTED_NOT_TAKEN_r11 929 +#define _INSTRUMENTED_NOT_TAKEN_r22 930 +#define _INSTRUMENTED_NOT_TAKEN_r33 931 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 932 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 933 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 934 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 935 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 936 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 937 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 938 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 939 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 940 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 941 +#define _IS_NONE_r11 942 +#define _IS_OP_r21 943 +#define _ITER_CHECK_LIST_r02 944 +#define _ITER_CHECK_LIST_r12 945 +#define _ITER_CHECK_LIST_r22 946 +#define _ITER_CHECK_LIST_r33 947 +#define _ITER_CHECK_RANGE_r02 948 +#define _ITER_CHECK_RANGE_r12 949 +#define _ITER_CHECK_RANGE_r22 950 +#define _ITER_CHECK_RANGE_r33 951 +#define _ITER_CHECK_TUPLE_r02 952 +#define _ITER_CHECK_TUPLE_r12 953 +#define _ITER_CHECK_TUPLE_r22 954 +#define _ITER_CHECK_TUPLE_r33 955 +#define _ITER_JUMP_LIST_r02 956 +#define _ITER_JUMP_LIST_r12 957 +#define _ITER_JUMP_LIST_r22 958 +#define _ITER_JUMP_LIST_r33 959 +#define _ITER_JUMP_RANGE_r02 960 +#define _ITER_JUMP_RANGE_r12 961 +#define _ITER_JUMP_RANGE_r22 962 +#define _ITER_JUMP_RANGE_r33 963 +#define _ITER_JUMP_TUPLE_r02 964 +#define _ITER_JUMP_TUPLE_r12 965 +#define _ITER_JUMP_TUPLE_r22 966 +#define _ITER_JUMP_TUPLE_r33 967 +#define _ITER_NEXT_LIST_r23 968 +#define _ITER_NEXT_LIST_TIER_TWO_r23 969 +#define _ITER_NEXT_RANGE_r03 970 +#define _ITER_NEXT_RANGE_r13 971 +#define _ITER_NEXT_RANGE_r23 972 +#define _ITER_NEXT_TUPLE_r03 973 +#define _ITER_NEXT_TUPLE_r13 974 +#define _ITER_NEXT_TUPLE_r23 975 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 976 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 977 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 978 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 979 +#define _JUMP_TO_TOP_r00 980 +#define _LIST_APPEND_r10 981 +#define _LIST_EXTEND_r10 982 +#define _LOAD_ATTR_r10 983 +#define _LOAD_ATTR_CLASS_r11 984 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 985 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 986 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 987 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 988 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 989 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 990 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 991 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 992 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 993 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 994 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 995 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 996 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 997 +#define _LOAD_ATTR_MODULE_r11 998 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 999 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1000 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1001 +#define _LOAD_ATTR_SLOT_r11 1002 +#define _LOAD_ATTR_WITH_HINT_r11 1003 +#define _LOAD_BUILD_CLASS_r01 1004 +#define _LOAD_BYTECODE_r00 1005 +#define _LOAD_COMMON_CONSTANT_r01 1006 +#define _LOAD_COMMON_CONSTANT_r12 1007 +#define _LOAD_COMMON_CONSTANT_r23 1008 +#define _LOAD_CONST_r01 1009 +#define _LOAD_CONST_r12 1010 +#define _LOAD_CONST_r23 1011 +#define _LOAD_CONST_INLINE_r01 1012 +#define _LOAD_CONST_INLINE_r12 1013 +#define _LOAD_CONST_INLINE_r23 1014 +#define _LOAD_CONST_INLINE_BORROW_r01 1015 +#define _LOAD_CONST_INLINE_BORROW_r12 1016 +#define _LOAD_CONST_INLINE_BORROW_r23 1017 +#define _LOAD_CONST_UNDER_INLINE_r02 1018 +#define _LOAD_CONST_UNDER_INLINE_r12 1019 +#define _LOAD_CONST_UNDER_INLINE_r23 1020 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1021 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1022 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1023 +#define _LOAD_DEREF_r01 1024 +#define _LOAD_FAST_r01 1025 +#define _LOAD_FAST_r12 1026 +#define _LOAD_FAST_r23 1027 +#define _LOAD_FAST_0_r01 1028 +#define _LOAD_FAST_0_r12 1029 +#define _LOAD_FAST_0_r23 1030 +#define _LOAD_FAST_1_r01 1031 +#define _LOAD_FAST_1_r12 1032 +#define _LOAD_FAST_1_r23 1033 +#define _LOAD_FAST_2_r01 1034 +#define _LOAD_FAST_2_r12 1035 +#define _LOAD_FAST_2_r23 1036 +#define _LOAD_FAST_3_r01 1037 +#define _LOAD_FAST_3_r12 1038 +#define _LOAD_FAST_3_r23 1039 +#define _LOAD_FAST_4_r01 1040 +#define _LOAD_FAST_4_r12 1041 +#define _LOAD_FAST_4_r23 1042 +#define _LOAD_FAST_5_r01 1043 +#define _LOAD_FAST_5_r12 1044 +#define _LOAD_FAST_5_r23 1045 +#define _LOAD_FAST_6_r01 1046 +#define _LOAD_FAST_6_r12 1047 +#define _LOAD_FAST_6_r23 1048 +#define _LOAD_FAST_7_r01 1049 +#define _LOAD_FAST_7_r12 1050 +#define _LOAD_FAST_7_r23 1051 +#define _LOAD_FAST_AND_CLEAR_r01 1052 +#define _LOAD_FAST_AND_CLEAR_r12 1053 +#define _LOAD_FAST_AND_CLEAR_r23 1054 +#define _LOAD_FAST_BORROW_r01 1055 +#define _LOAD_FAST_BORROW_r12 1056 +#define _LOAD_FAST_BORROW_r23 1057 +#define _LOAD_FAST_BORROW_0_r01 1058 +#define _LOAD_FAST_BORROW_0_r12 1059 +#define _LOAD_FAST_BORROW_0_r23 1060 +#define _LOAD_FAST_BORROW_1_r01 1061 +#define _LOAD_FAST_BORROW_1_r12 1062 +#define _LOAD_FAST_BORROW_1_r23 1063 +#define _LOAD_FAST_BORROW_2_r01 1064 +#define _LOAD_FAST_BORROW_2_r12 1065 +#define _LOAD_FAST_BORROW_2_r23 1066 +#define _LOAD_FAST_BORROW_3_r01 1067 +#define _LOAD_FAST_BORROW_3_r12 1068 +#define _LOAD_FAST_BORROW_3_r23 1069 +#define _LOAD_FAST_BORROW_4_r01 1070 +#define _LOAD_FAST_BORROW_4_r12 1071 +#define _LOAD_FAST_BORROW_4_r23 1072 +#define _LOAD_FAST_BORROW_5_r01 1073 +#define _LOAD_FAST_BORROW_5_r12 1074 +#define _LOAD_FAST_BORROW_5_r23 1075 +#define _LOAD_FAST_BORROW_6_r01 1076 +#define _LOAD_FAST_BORROW_6_r12 1077 +#define _LOAD_FAST_BORROW_6_r23 1078 +#define _LOAD_FAST_BORROW_7_r01 1079 +#define _LOAD_FAST_BORROW_7_r12 1080 +#define _LOAD_FAST_BORROW_7_r23 1081 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1082 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1083 +#define _LOAD_FAST_CHECK_r01 1084 +#define _LOAD_FAST_CHECK_r12 1085 +#define _LOAD_FAST_CHECK_r23 1086 +#define _LOAD_FAST_LOAD_FAST_r02 1087 +#define _LOAD_FAST_LOAD_FAST_r13 1088 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1089 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1090 +#define _LOAD_GLOBAL_r00 1091 +#define _LOAD_GLOBAL_BUILTINS_r01 1092 +#define _LOAD_GLOBAL_MODULE_r01 1093 +#define _LOAD_LOCALS_r01 1094 +#define _LOAD_LOCALS_r12 1095 +#define _LOAD_LOCALS_r23 1096 +#define _LOAD_NAME_r01 1097 +#define _LOAD_SMALL_INT_r01 1098 +#define _LOAD_SMALL_INT_r12 1099 +#define _LOAD_SMALL_INT_r23 1100 +#define _LOAD_SMALL_INT_0_r01 1101 +#define _LOAD_SMALL_INT_0_r12 1102 +#define _LOAD_SMALL_INT_0_r23 1103 +#define _LOAD_SMALL_INT_1_r01 1104 +#define _LOAD_SMALL_INT_1_r12 1105 +#define _LOAD_SMALL_INT_1_r23 1106 +#define _LOAD_SMALL_INT_2_r01 1107 +#define _LOAD_SMALL_INT_2_r12 1108 +#define _LOAD_SMALL_INT_2_r23 1109 +#define _LOAD_SMALL_INT_3_r01 1110 +#define _LOAD_SMALL_INT_3_r12 1111 +#define _LOAD_SMALL_INT_3_r23 1112 +#define _LOAD_SPECIAL_r00 1113 +#define _LOAD_SUPER_ATTR_ATTR_r31 1114 +#define _LOAD_SUPER_ATTR_METHOD_r32 1115 +#define _MAKE_CALLARGS_A_TUPLE_r33 1116 +#define _MAKE_CELL_r00 1117 +#define _MAKE_FUNCTION_r11 1118 +#define _MAKE_WARM_r00 1119 +#define _MAKE_WARM_r11 1120 +#define _MAKE_WARM_r22 1121 +#define _MAKE_WARM_r33 1122 +#define _MAP_ADD_r20 1123 +#define _MATCH_CLASS_r31 1124 +#define _MATCH_KEYS_r23 1125 +#define _MATCH_MAPPING_r02 1126 +#define _MATCH_MAPPING_r12 1127 +#define _MATCH_MAPPING_r23 1128 +#define _MATCH_SEQUENCE_r02 1129 +#define _MATCH_SEQUENCE_r12 1130 +#define _MATCH_SEQUENCE_r23 1131 +#define _MAYBE_EXPAND_METHOD_r00 1132 +#define _MAYBE_EXPAND_METHOD_KW_r11 1133 +#define _MONITOR_CALL_r00 1134 +#define _MONITOR_CALL_KW_r11 1135 +#define _MONITOR_JUMP_BACKWARD_r00 1136 +#define _MONITOR_JUMP_BACKWARD_r11 1137 +#define _MONITOR_JUMP_BACKWARD_r22 1138 +#define _MONITOR_JUMP_BACKWARD_r33 1139 +#define _MONITOR_RESUME_r00 1140 +#define _NOP_r00 1141 +#define _NOP_r11 1142 +#define _NOP_r22 1143 +#define _NOP_r33 1144 +#define _POP_CALL_r20 1145 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1146 +#define _POP_CALL_ONE_r30 1147 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1148 +#define _POP_CALL_TWO_r30 1149 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1150 +#define _POP_EXCEPT_r10 1151 +#define _POP_ITER_r20 1152 +#define _POP_JUMP_IF_FALSE_r00 1153 +#define _POP_JUMP_IF_FALSE_r10 1154 +#define _POP_JUMP_IF_FALSE_r21 1155 +#define _POP_JUMP_IF_FALSE_r32 1156 +#define _POP_JUMP_IF_TRUE_r00 1157 +#define _POP_JUMP_IF_TRUE_r10 1158 +#define _POP_JUMP_IF_TRUE_r21 1159 +#define _POP_JUMP_IF_TRUE_r32 1160 +#define _POP_TOP_r10 1161 +#define _POP_TOP_FLOAT_r00 1162 +#define _POP_TOP_FLOAT_r10 1163 +#define _POP_TOP_FLOAT_r21 1164 +#define _POP_TOP_FLOAT_r32 1165 +#define _POP_TOP_INT_r00 1166 +#define _POP_TOP_INT_r10 1167 +#define _POP_TOP_INT_r21 1168 +#define _POP_TOP_INT_r32 1169 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1170 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1171 +#define _POP_TOP_NOP_r00 1172 +#define _POP_TOP_NOP_r10 1173 +#define _POP_TOP_NOP_r21 1174 +#define _POP_TOP_NOP_r32 1175 +#define _POP_TOP_UNICODE_r00 1176 +#define _POP_TOP_UNICODE_r10 1177 +#define _POP_TOP_UNICODE_r21 1178 +#define _POP_TOP_UNICODE_r32 1179 +#define _POP_TWO_r20 1180 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1181 +#define _PUSH_EXC_INFO_r02 1182 +#define _PUSH_EXC_INFO_r12 1183 +#define _PUSH_EXC_INFO_r23 1184 +#define _PUSH_FRAME_r10 1185 +#define _PUSH_NULL_r01 1186 +#define _PUSH_NULL_r12 1187 +#define _PUSH_NULL_r23 1188 +#define _PUSH_NULL_CONDITIONAL_r00 1189 +#define _PY_FRAME_GENERAL_r01 1190 +#define _PY_FRAME_KW_r11 1191 +#define _QUICKEN_RESUME_r00 1192 +#define _QUICKEN_RESUME_r11 1193 +#define _QUICKEN_RESUME_r22 1194 +#define _QUICKEN_RESUME_r33 1195 +#define _REPLACE_WITH_TRUE_r11 1196 +#define _RESUME_CHECK_r00 1197 +#define _RESUME_CHECK_r11 1198 +#define _RESUME_CHECK_r22 1199 +#define _RESUME_CHECK_r33 1200 +#define _RETURN_GENERATOR_r01 1201 +#define _RETURN_VALUE_r11 1202 +#define _SAVE_RETURN_OFFSET_r00 1203 +#define _SAVE_RETURN_OFFSET_r11 1204 +#define _SAVE_RETURN_OFFSET_r22 1205 +#define _SAVE_RETURN_OFFSET_r33 1206 +#define _SEND_r22 1207 +#define _SEND_GEN_FRAME_r22 1208 +#define _SETUP_ANNOTATIONS_r00 1209 +#define _SET_ADD_r10 1210 +#define _SET_FUNCTION_ATTRIBUTE_r01 1211 +#define _SET_FUNCTION_ATTRIBUTE_r11 1212 +#define _SET_FUNCTION_ATTRIBUTE_r21 1213 +#define _SET_FUNCTION_ATTRIBUTE_r32 1214 +#define _SET_IP_r00 1215 +#define _SET_IP_r11 1216 +#define _SET_IP_r22 1217 +#define _SET_IP_r33 1218 +#define _SET_UPDATE_r10 1219 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1220 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1221 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1222 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1223 +#define _SPILL_OR_RELOAD_r01 1224 +#define _SPILL_OR_RELOAD_r02 1225 +#define _SPILL_OR_RELOAD_r03 1226 +#define _SPILL_OR_RELOAD_r10 1227 +#define _SPILL_OR_RELOAD_r12 1228 +#define _SPILL_OR_RELOAD_r13 1229 +#define _SPILL_OR_RELOAD_r20 1230 +#define _SPILL_OR_RELOAD_r21 1231 +#define _SPILL_OR_RELOAD_r23 1232 +#define _SPILL_OR_RELOAD_r30 1233 +#define _SPILL_OR_RELOAD_r31 1234 +#define _SPILL_OR_RELOAD_r32 1235 +#define _START_EXECUTOR_r00 1236 +#define _STORE_ATTR_r20 1237 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1238 +#define _STORE_ATTR_SLOT_r21 1239 +#define _STORE_ATTR_WITH_HINT_r21 1240 +#define _STORE_DEREF_r10 1241 +#define _STORE_FAST_r10 1242 +#define _STORE_FAST_0_r10 1243 +#define _STORE_FAST_1_r10 1244 +#define _STORE_FAST_2_r10 1245 +#define _STORE_FAST_3_r10 1246 +#define _STORE_FAST_4_r10 1247 +#define _STORE_FAST_5_r10 1248 +#define _STORE_FAST_6_r10 1249 +#define _STORE_FAST_7_r10 1250 +#define _STORE_FAST_LOAD_FAST_r11 1251 +#define _STORE_FAST_STORE_FAST_r20 1252 +#define _STORE_GLOBAL_r10 1253 +#define _STORE_NAME_r10 1254 +#define _STORE_SLICE_r30 1255 +#define _STORE_SUBSCR_r30 1256 +#define _STORE_SUBSCR_DICT_r31 1257 +#define _STORE_SUBSCR_LIST_INT_r32 1258 +#define _SWAP_r11 1259 +#define _SWAP_2_r02 1260 +#define _SWAP_2_r12 1261 +#define _SWAP_2_r22 1262 +#define _SWAP_2_r33 1263 +#define _SWAP_3_r03 1264 +#define _SWAP_3_r13 1265 +#define _SWAP_3_r23 1266 +#define _SWAP_3_r33 1267 +#define _TIER2_RESUME_CHECK_r00 1268 +#define _TIER2_RESUME_CHECK_r11 1269 +#define _TIER2_RESUME_CHECK_r22 1270 +#define _TIER2_RESUME_CHECK_r33 1271 +#define _TO_BOOL_r11 1272 +#define _TO_BOOL_BOOL_r01 1273 +#define _TO_BOOL_BOOL_r11 1274 +#define _TO_BOOL_BOOL_r22 1275 +#define _TO_BOOL_BOOL_r33 1276 +#define _TO_BOOL_INT_r11 1277 +#define _TO_BOOL_LIST_r11 1278 +#define _TO_BOOL_NONE_r01 1279 +#define _TO_BOOL_NONE_r11 1280 +#define _TO_BOOL_NONE_r22 1281 +#define _TO_BOOL_NONE_r33 1282 +#define _TO_BOOL_STR_r11 1283 +#define _TRACE_RECORD_r00 1284 +#define _UNARY_INVERT_r11 1285 +#define _UNARY_NEGATIVE_r11 1286 +#define _UNARY_NOT_r01 1287 +#define _UNARY_NOT_r11 1288 +#define _UNARY_NOT_r22 1289 +#define _UNARY_NOT_r33 1290 +#define _UNPACK_EX_r10 1291 +#define _UNPACK_SEQUENCE_r10 1292 +#define _UNPACK_SEQUENCE_LIST_r10 1293 +#define _UNPACK_SEQUENCE_TUPLE_r10 1294 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1295 +#define _WITH_EXCEPT_START_r33 1296 +#define _YIELD_VALUE_r11 1297 +#define MAX_UOP_REGS_ID 1297 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 1281eeb041daab..ec374dd5818432 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -2131,10 +2131,10 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { }, }, [_FOR_ITER_GEN_FRAME] = { - .best = { 2, 2, 2, 2 }, + .best = { 0, 1, 2, 2 }, .entries = { - { -1, -1, -1 }, - { -1, -1, -1 }, + { 3, 0, _FOR_ITER_GEN_FRAME_r03 }, + { 3, 1, _FOR_ITER_GEN_FRAME_r13 }, { 3, 2, _FOR_ITER_GEN_FRAME_r23 }, { -1, -1, -1 }, }, @@ -3620,6 +3620,8 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_ITER_NEXT_RANGE_r03] = _ITER_NEXT_RANGE, [_ITER_NEXT_RANGE_r13] = _ITER_NEXT_RANGE, [_ITER_NEXT_RANGE_r23] = _ITER_NEXT_RANGE, + [_FOR_ITER_GEN_FRAME_r03] = _FOR_ITER_GEN_FRAME, + [_FOR_ITER_GEN_FRAME_r13] = _FOR_ITER_GEN_FRAME, [_FOR_ITER_GEN_FRAME_r23] = _FOR_ITER_GEN_FRAME, [_INSERT_NULL_r10] = _INSERT_NULL, [_LOAD_SPECIAL_r00] = _LOAD_SPECIAL, @@ -4182,6 +4184,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_FORMAT_WITH_SPEC] = "_FORMAT_WITH_SPEC", [_FORMAT_WITH_SPEC_r21] = "_FORMAT_WITH_SPEC_r21", [_FOR_ITER_GEN_FRAME] = "_FOR_ITER_GEN_FRAME", + [_FOR_ITER_GEN_FRAME_r03] = "_FOR_ITER_GEN_FRAME_r03", + [_FOR_ITER_GEN_FRAME_r13] = "_FOR_ITER_GEN_FRAME_r13", [_FOR_ITER_GEN_FRAME_r23] = "_FOR_ITER_GEN_FRAME_r23", [_FOR_ITER_TIER_TWO] = "_FOR_ITER_TIER_TWO", [_FOR_ITER_TIER_TWO_r23] = "_FOR_ITER_TIER_TWO_r23", diff --git a/Lib/test/test_free_threading/test_generators.py b/Lib/test/test_free_threading/test_generators.py index d01675eb38b370..11f59301bcd51d 100644 --- a/Lib/test/test_free_threading/test_generators.py +++ b/Lib/test/test_free_threading/test_generators.py @@ -49,3 +49,74 @@ def test_concurrent_write(self): self.concurrent_write_with_func(func=set_gen_name) with self.subTest(func=set_gen_qualname): self.concurrent_write_with_func(func=set_gen_qualname) + + def test_concurrent_send(self): + def gen(): + yield 1 + yield 2 + yield 3 + yield 4 + yield 5 + + def run_test(drive_generator): + g = gen() + values = [] + threading_helper.run_concurrently(drive_generator, self.NUM_THREADS, args=(g, values,)) + self.assertEqual(sorted(values), [1, 2, 3, 4, 5]) + + def call_next(g, values): + while True: + try: + values.append(next(g)) + except ValueError: + continue + except StopIteration: + break + + with self.subTest(method='next'): + run_test(call_next) + + def call_send(g, values): + while True: + try: + values.append(g.send(None)) + except ValueError: + continue + except StopIteration: + break + + with self.subTest(method='send'): + run_test(call_send) + + def for_iter_gen(g, values): + while True: + try: + for value in g: + values.append(value) + else: + break + except ValueError: + continue + + with self.subTest(method='for'): + run_test(for_iter_gen) + + def test_concurrent_close(self): + def gen(): + for i in range(10): + yield i + time.sleep(0.001) + + def drive_generator(g): + while True: + try: + for value in g: + if value == 5: + g.close() + else: + return + except ValueError as e: + self.assertEqual(e.args[0], "generator already executing") + + g = gen() + threading_helper.run_concurrently(drive_generator, self.NUM_THREADS, args=(g,)) diff --git a/Objects/genobject.c b/Objects/genobject.c index 3694198289de8c..508d215a0cfe64 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -36,6 +36,14 @@ static PyObject* async_gen_athrow_new(PyAsyncGenObject *, PyObject *); #define _PyAsyncGenObject_CAST(op) \ _Py_CAST(PyAsyncGenObject*, (op)) +#ifdef Py_GIL_DISABLED +# define _Py_GEN_TRY_SET_FRAME_STATE(gen, expected, state) \ + _Py_atomic_compare_exchange_int8(&(gen)->gi_frame_state, &expected, (state)) +#else +# define _Py_GEN_TRY_SET_FRAME_STATE(gen, expected, state) \ + ((gen)->gi_frame_state = (state), true) +#endif + static const char *NON_INIT_CORO_MSG = "can't send non-None value to a " "just-started coroutine"; @@ -145,10 +153,7 @@ _PyGen_Finalize(PyObject *self) static void gen_clear_frame(PyGenObject *gen) { - if (gen->gi_frame_state == FRAME_CLEARED) - return; - - gen->gi_frame_state = FRAME_CLEARED; + assert(gen->gi_frame_state == FRAME_CLEARED); _PyInterpreterFrame *frame = &gen->gi_iframe; frame->previous = NULL; _PyFrame_ClearExceptCode(frame); @@ -179,7 +184,10 @@ gen_dealloc(PyObject *self) if (PyCoro_CheckExact(gen)) { Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer); } - gen_clear_frame(gen); + if (gen->gi_frame_state != FRAME_CLEARED) { + gen->gi_frame_state = FRAME_CLEARED; + gen_clear_frame(gen); + } assert(gen->gi_exc_state.exc_value == NULL); PyStackRef_CLEAR(gen->gi_iframe.f_executable); Py_CLEAR(gen->gi_name); @@ -188,58 +196,31 @@ gen_dealloc(PyObject *self) PyObject_GC_Del(gen); } -static PySendResult -gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, - int exc, int closing) +static void +gen_raise_already_executing_error(PyGenObject *gen) { - PyThreadState *tstate = _PyThreadState_GET(); - _PyInterpreterFrame *frame = &gen->gi_iframe; - - *presult = NULL; - if (gen->gi_frame_state == FRAME_CREATED && arg && arg != Py_None) { - const char *msg = "can't send non-None value to a " - "just-started generator"; - if (PyCoro_CheckExact(gen)) { - msg = NON_INIT_CORO_MSG; - } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "can't send non-None value to a " - "just-started async generator"; - } - PyErr_SetString(PyExc_TypeError, msg); - return PYGEN_ERROR; - } - if (gen->gi_frame_state == FRAME_EXECUTING) { - const char *msg = "generator already executing"; - if (PyCoro_CheckExact(gen)) { - msg = "coroutine already executing"; - } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "async generator already executing"; - } - PyErr_SetString(PyExc_ValueError, msg); - return PYGEN_ERROR; + const char *msg = "generator already executing"; + if (PyCoro_CheckExact(gen)) { + msg = "coroutine already executing"; } - if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { - if (PyCoro_CheckExact(gen) && !closing) { - /* `gen` is an exhausted coroutine: raise an error, - except when called from gen_close(), which should - always be a silent method. */ - PyErr_SetString( - PyExc_RuntimeError, - "cannot reuse already awaited coroutine"); - } - else if (arg && !exc) { - /* `gen` is an exhausted generator: - only return value if called from send(). */ - *presult = Py_NewRef(Py_None); - return PYGEN_RETURN; - } - return PYGEN_ERROR; + else if (PyAsyncGen_CheckExact(gen)) { + msg = "async generator already executing"; } + PyErr_SetString(PyExc_ValueError, msg); +} + +// Send 'arg' into 'gen'. On success, return PYGEN_NEXT or PYGEN_RETURN. +// Returns PYGEN_ERROR on failure. 'presult' is set to the yielded or +// returned value. +// The generator must be in the FRAME_EXECUTING state when this function +// is called. +static PySendResult +gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, int exc) +{ + assert(FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state) == FRAME_EXECUTING); - assert((gen->gi_frame_state == FRAME_CREATED) || - FRAME_STATE_SUSPENDED(gen->gi_frame_state)); + PyThreadState *tstate = _PyThreadState_GET(); + _PyInterpreterFrame *frame = &gen->gi_iframe; /* Push arg onto the frame's value stack */ PyObject *arg_obj = arg ? arg : Py_None; @@ -254,21 +235,34 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, _PyErr_ChainStackItem(); } - gen->gi_frame_state = FRAME_EXECUTING; EVAL_CALL_STAT_INC(EVAL_CALL_GENERATOR); PyObject *result = _PyEval_EvalFrame(tstate, frame, exc); assert(tstate->exc_info == prev_exc_info); +#ifndef Py_GIL_DISABLED assert(gen->gi_exc_state.previous_item == NULL); - assert(gen->gi_frame_state != FRAME_EXECUTING); assert(frame->previous == NULL); + assert(gen->gi_frame_state != FRAME_EXECUTING); +#endif + + // The generator_return_kind field is used to distinguish between a + // yield and a return from within _PyEval_EvalFrame(). Earlier versions + // of CPython (prior to 3.15) used gi_frame_state for this purpose, but + // that requires the GIL for thread-safety. + int return_kind = ((_PyThreadStateImpl *)tstate)->generator_return_kind; + + if (return_kind == GENERATOR_YIELD) { + assert(result != NULL && !_PyErr_Occurred(tstate)); + *presult = result; + return PYGEN_NEXT; + } + + assert(return_kind == GENERATOR_RETURN); + assert(gen->gi_exc_state.exc_value == NULL); + assert(FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state) == FRAME_CLEARED); /* If the generator just returned (as opposed to yielding), signal * that the generator is exhausted. */ if (result) { - if (FRAME_STATE_SUSPENDED(gen->gi_frame_state)) { - *presult = result; - return PYGEN_NEXT; - } assert(result == Py_None || !PyAsyncGen_CheckExact(gen)); if (result == Py_None && !PyAsyncGen_CheckExact(gen) && !arg) { /* Return NULL if called by gen_iternext() */ @@ -281,37 +275,82 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, !PyErr_ExceptionMatches(PyExc_StopAsyncIteration)); } - assert(gen->gi_exc_state.exc_value == NULL); - assert(gen->gi_frame_state == FRAME_CLEARED); *presult = result; return result ? PYGEN_RETURN : PYGEN_ERROR; } +// Set the generator 'gen' to the executing state and send 'arg' into it. +// See gen_send_ex2() for details. +static PySendResult +gen_send_ex(PyGenObject *gen, PyObject *arg, PyObject **presult) +{ + *presult = NULL; + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + do { + if (frame_state == FRAME_CREATED && arg && arg != Py_None) { + const char *msg = "can't send non-None value to a " + "just-started generator"; + if (PyCoro_CheckExact(gen)) { + msg = NON_INIT_CORO_MSG; + } + else if (PyAsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a " + "just-started async generator"; + } + PyErr_SetString(PyExc_TypeError, msg); + return PYGEN_ERROR; + } + if (frame_state == FRAME_EXECUTING) { + gen_raise_already_executing_error(gen); + return PYGEN_ERROR; + } + if (FRAME_STATE_FINISHED(frame_state)) { + if (PyCoro_CheckExact(gen)) { + /* `gen` is an exhausted coroutine: raise an error, + except when called from gen_close(), which should + always be a silent method. */ + PyErr_SetString( + PyExc_RuntimeError, + "cannot reuse already awaited coroutine"); + } + else if (arg) { + /* `gen` is an exhausted generator: + only return value if called from send(). */ + *presult = Py_None; + return PYGEN_RETURN; + } + return PYGEN_ERROR; + } + + assert((frame_state == FRAME_CREATED) || + FRAME_STATE_SUSPENDED(frame_state)); + } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_EXECUTING)); + + return gen_send_ex2(gen, arg, presult, 0); +} + static PySendResult PyGen_am_send(PyObject *self, PyObject *arg, PyObject **result) { PyGenObject *gen = _PyGen_CAST(self); - return gen_send_ex2(gen, arg, result, 0, 0); + return gen_send_ex(gen, arg, result); } static PyObject * -gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) +gen_set_stop_iteration(PyGenObject *gen, PyObject *result) { - PyObject *result; - if (gen_send_ex2(gen, arg, &result, exc, closing) == PYGEN_RETURN) { - if (PyAsyncGen_CheckExact(gen)) { - assert(result == Py_None); - PyErr_SetNone(PyExc_StopAsyncIteration); - } - else if (result == Py_None) { - PyErr_SetNone(PyExc_StopIteration); - } - else { - _PyGen_SetStopIterationValue(result); - } - Py_CLEAR(result); + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); } - return result; + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { + _PyGen_SetStopIterationValue(result); + } + Py_DECREF(result); + return NULL; } PyDoc_STRVAR(send_doc, @@ -319,9 +358,14 @@ PyDoc_STRVAR(send_doc, return next yielded value or raise StopIteration."); static PyObject * -gen_send(PyObject *gen, PyObject *arg) +gen_send(PyObject *op, PyObject *arg) { - return gen_send_ex((PyGenObject*)gen, arg, 0, 0); + PyObject *result; + PyGenObject *gen = _PyGen_CAST(op); + if (gen_send_ex(gen, arg, &result) == PYGEN_RETURN) { + return gen_set_stop_iteration(gen, result); + } + return result; } PyDoc_STRVAR(close_doc, @@ -370,43 +414,43 @@ is_resume(_Py_CODEUNIT *instr) ); } -PyObject * -_PyGen_yf(PyGenObject *gen) -{ - if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) { - _PyInterpreterFrame *frame = &gen->gi_iframe; - // GH-122390: These asserts are wrong in the presence of ENTER_EXECUTOR! - // assert(is_resume(frame->instr_ptr)); - // assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM); - return PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(frame)); - } - return NULL; -} - static PyObject * gen_close(PyObject *self, PyObject *args) { PyGenObject *gen = _PyGen_CAST(self); - if (gen->gi_frame_state == FRAME_CREATED) { - gen->gi_frame_state = FRAME_COMPLETED; - gen_clear_frame(gen); - Py_RETURN_NONE; - } - if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { - Py_RETURN_NONE; - } + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + do { + if (frame_state == FRAME_CREATED) { + if (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_CLEARED)) { + continue; + } + gen_clear_frame(gen); + Py_RETURN_NONE; + } + + if (FRAME_STATE_FINISHED(frame_state)) { + Py_RETURN_NONE; + } + + if (frame_state == FRAME_EXECUTING) { + gen_raise_already_executing_error(gen); + return NULL; + } + + assert(frame_state == FRAME_SUSPENDED_YIELD_FROM || + frame_state == FRAME_SUSPENDED); + + } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_EXECUTING)); - PyObject *yf = _PyGen_yf(gen); int err = 0; - if (yf) { - PyFrameState state = gen->gi_frame_state; - gen->gi_frame_state = FRAME_EXECUTING; + _PyInterpreterFrame *frame = &gen->gi_iframe; + if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { + PyObject *yf = PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(frame)); err = gen_close_iter(yf); - gen->gi_frame_state = state; Py_DECREF(yf); } - _PyInterpreterFrame *frame = &gen->gi_iframe; + if (is_resume(frame->instr_ptr)) { bool no_unwind_tools = _PyEval_NoToolsForUnwind(_PyThreadState_GET()); /* We can safely ignore the outermost try block @@ -416,7 +460,7 @@ gen_close(PyObject *self, PyObject *args) if (oparg & RESUME_OPARG_DEPTH1_MASK && no_unwind_tools) { // RESUME after YIELD_VALUE and exception depth is 1 assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); - gen->gi_frame_state = FRAME_COMPLETED; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_CLEARED); gen_clear_frame(gen); Py_RETURN_NONE; } @@ -425,8 +469,13 @@ gen_close(PyObject *self, PyObject *args) PyErr_SetNone(PyExc_GeneratorExit); } - PyObject *retval = gen_send_ex(gen, Py_None, 1, 1); - if (retval) { + PyObject *retval; + if (gen_send_ex2(gen, Py_None, &retval, 1) == PYGEN_RETURN) { + // the generator returned a value while closing, return the value here + assert(!PyErr_Occurred()); + return retval; + } + else if (retval) { const char *msg = "generator ignored GeneratorExit"; if (PyCoro_CheckExact(gen)) { msg = "coroutine ignored GeneratorExit"; @@ -443,15 +492,80 @@ gen_close(PyObject *self, PyObject *args) PyErr_Clear(); /* ignore this error */ Py_RETURN_NONE; } + return NULL; +} - /* if the generator returned a value while closing, StopIteration was - * raised in gen_send_ex() above; retrieve and return the value here */ - if (_PyGen_FetchStopIterationValue(&retval) == 0) { - return retval; +// Set an exception for a gen.throw() call. +// Return 0 on success, -1 on failure. +static int +gen_set_exception(PyObject *typ, PyObject *val, PyObject *tb) +{ + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + tb = NULL; } - return NULL; + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "throw() third argument must be a traceback object"); + return -1; + } + + Py_INCREF(typ); + Py_XINCREF(val); + Py_XINCREF(tb); + + if (PyExceptionClass_Check(typ)) { + PyErr_NormalizeException(&typ, &val, &tb); + } + else if (PyExceptionInstance_Check(typ)) { + /* Raising an instance. The value should be a dummy. */ + if (val && val != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto failed_throw; + } + else { + /* Normalize to raise , */ + Py_XSETREF(val, typ); + typ = Py_NewRef(PyExceptionInstance_Class(typ)); + + if (tb == NULL) + /* Returns NULL if there's no traceback */ + tb = PyException_GetTraceback(val); + } + } + else { + /* Not something you can raise. throw() fails. */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes or instances " + "deriving from BaseException, not %s", + Py_TYPE(typ)->tp_name); + goto failed_throw; + } + + PyErr_Restore(typ, val, tb); + return 0; + +failed_throw: + /* Didn't use our arguments, so restore their original refcounts */ + Py_DECREF(typ); + Py_XDECREF(val); + Py_XDECREF(tb); + return -1; } +static PyObject * +gen_throw_current_exception(PyGenObject *gen) +{ + assert(gen->gi_frame_state == FRAME_EXECUTING); + + PyObject *result; + if (gen_send_ex2(gen, Py_None, &result, 1) == PYGEN_RETURN) { + return gen_set_stop_iteration(gen, result); + } + return result; +} PyDoc_STRVAR(throw_doc, "throw(value)\n\ @@ -466,10 +580,32 @@ static PyObject * _gen_throw(PyGenObject *gen, int close_on_genexit, PyObject *typ, PyObject *val, PyObject *tb) { - PyObject *yf = _PyGen_yf(gen); + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + do { + if (frame_state == FRAME_EXECUTING) { + gen_raise_already_executing_error(gen); + return NULL; + } - if (yf) { + if (FRAME_STATE_FINISHED(frame_state)) { + if (PyCoro_CheckExact(gen)) { + /* `gen` is an exhausted coroutine: raise an error */ + PyErr_SetString( + PyExc_RuntimeError, + "cannot reuse already awaited coroutine"); + return NULL; + } + gen_set_exception(typ, val, tb); + return NULL; + } + + assert((frame_state == FRAME_CREATED) || + FRAME_STATE_SUSPENDED(frame_state)); + } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_EXECUTING)); + + if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { _PyInterpreterFrame *frame = &gen->gi_iframe; + PyObject *yf = PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(frame)); PyObject *ret; int err; if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && @@ -479,13 +615,11 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, We have to allow some awaits to work it through, hence the `close_on_genexit` parameter here. */ - PyFrameState state = gen->gi_frame_state; - gen->gi_frame_state = FRAME_EXECUTING; err = gen_close_iter(yf); - gen->gi_frame_state = state; Py_DECREF(yf); - if (err < 0) - return gen_send_ex(gen, Py_None, 1, 0); + if (err < 0) { + return gen_throw_current_exception(gen); + } goto throw_here; } PyThreadState *tstate = _PyThreadState_GET(); @@ -501,18 +635,17 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, tstate->current_frame = frame; /* Close the generator that we are currently iterating with 'yield from' or awaiting on with 'await'. */ - PyFrameState state = gen->gi_frame_state; - gen->gi_frame_state = FRAME_EXECUTING; ret = _gen_throw((PyGenObject *)yf, close_on_genexit, typ, val, tb); - gen->gi_frame_state = state; tstate->current_frame = prev; frame->previous = NULL; - } else { + } + else { /* `yf` is an iterator or a coroutine-like object. */ PyObject *meth; if (PyObject_GetOptionalAttr(yf, &_Py_ID(throw), &meth) < 0) { Py_DECREF(yf); + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, frame_state); return NULL; } if (meth == NULL) { @@ -523,75 +656,26 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, _PyInterpreterFrame *prev = tstate->current_frame; frame->previous = prev; tstate->current_frame = frame; - PyFrameState state = gen->gi_frame_state; - gen->gi_frame_state = FRAME_EXECUTING; ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); - gen->gi_frame_state = state; tstate->current_frame = prev; frame->previous = NULL; Py_DECREF(meth); } Py_DECREF(yf); if (!ret) { - ret = gen_send_ex(gen, Py_None, 1, 0); + return gen_throw_current_exception(gen); } + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, frame_state); return ret; } throw_here: - /* First, check the traceback argument, replacing None with - NULL. */ - if (tb == Py_None) { - tb = NULL; - } - else if (tb != NULL && !PyTraceBack_Check(tb)) { - PyErr_SetString(PyExc_TypeError, - "throw() third argument must be a traceback object"); + assert(FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state) == FRAME_EXECUTING); + if (gen_set_exception(typ, val, tb) < 0) { + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, frame_state); return NULL; } - - Py_INCREF(typ); - Py_XINCREF(val); - Py_XINCREF(tb); - - if (PyExceptionClass_Check(typ)) - PyErr_NormalizeException(&typ, &val, &tb); - - else if (PyExceptionInstance_Check(typ)) { - /* Raising an instance. The value should be a dummy. */ - if (val && val != Py_None) { - PyErr_SetString(PyExc_TypeError, - "instance exception may not have a separate value"); - goto failed_throw; - } - else { - /* Normalize to raise , */ - Py_XSETREF(val, typ); - typ = Py_NewRef(PyExceptionInstance_Class(typ)); - - if (tb == NULL) - /* Returns NULL if there's no traceback */ - tb = PyException_GetTraceback(val); - } - } - else { - /* Not something you can raise. throw() fails. */ - PyErr_Format(PyExc_TypeError, - "exceptions must be classes or instances " - "deriving from BaseException, not %s", - Py_TYPE(typ)->tp_name); - goto failed_throw; - } - - PyErr_Restore(typ, val, tb); - return gen_send_ex(gen, Py_None, 1, 0); - -failed_throw: - /* Didn't use our arguments, so restore their original refcounts */ - Py_DECREF(typ); - Py_XDECREF(val); - Py_XDECREF(tb); - return NULL; + return gen_throw_current_exception(gen); } @@ -633,7 +717,7 @@ gen_iternext(PyObject *self) PyGenObject *gen = _PyGen_CAST(self); PyObject *result; - if (gen_send_ex2(gen, NULL, &result, 0, 0) == PYGEN_RETURN) { + if (gen_send_ex(gen, NULL, &result) == PYGEN_RETURN) { if (result != Py_None) { _PyGen_SetStopIterationValue(result); } @@ -757,13 +841,15 @@ gen_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -gen_getyieldfrom(PyObject *gen, void *Py_UNUSED(ignored)) +gen_getyieldfrom(PyObject *self, void *Py_UNUSED(ignored)) { - PyObject *yf = _PyGen_yf(_PyGen_CAST(gen)); - if (yf == NULL) { + PyGenObject *gen = _PyGen_CAST(self); + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + if (frame_state != FRAME_SUSPENDED_YIELD_FROM) { Py_RETURN_NONE; } - return yf; + // TODO: still not thread-safe with free threading + return PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(&gen->gi_iframe)); } @@ -771,17 +857,16 @@ static PyObject * gen_getrunning(PyObject *self, void *Py_UNUSED(ignored)) { PyGenObject *gen = _PyGen_CAST(self); - if (gen->gi_frame_state == FRAME_EXECUTING) { - Py_RETURN_TRUE; - } - Py_RETURN_FALSE; + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + return frame_state == FRAME_EXECUTING ? Py_True : Py_False; } static PyObject * gen_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) { PyGenObject *gen = _PyGen_CAST(self); - return PyBool_FromLong(FRAME_STATE_SUSPENDED(gen->gi_frame_state)); + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + return FRAME_STATE_SUSPENDED(frame_state) ? Py_True : Py_False; } static PyObject * @@ -790,9 +875,11 @@ _gen_getframe(PyGenObject *gen, const char *const name) if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) { return NULL; } - if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); + if (FRAME_STATE_FINISHED(frame_state)) { Py_RETURN_NONE; } + // TODO: still not thread-safe with free threading return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(&gen->gi_iframe)); } @@ -1135,35 +1222,6 @@ coro_await(PyObject *coro) return (PyObject *)cw; } -static PyObject * -coro_get_cr_await(PyObject *coro, void *Py_UNUSED(ignored)) -{ - PyObject *yf = _PyGen_yf((PyGenObject *) coro); - if (yf == NULL) - Py_RETURN_NONE; - return yf; -} - -static PyObject * -cr_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) -{ - PyCoroObject *coro = _PyCoroObject_CAST(self); - if (FRAME_STATE_SUSPENDED(coro->cr_frame_state)) { - Py_RETURN_TRUE; - } - Py_RETURN_FALSE; -} - -static PyObject * -cr_getrunning(PyObject *self, void *Py_UNUSED(ignored)) -{ - PyCoroObject *coro = _PyCoroObject_CAST(self); - if (coro->cr_frame_state == FRAME_EXECUTING) { - Py_RETURN_TRUE; - } - Py_RETURN_FALSE; -} - static PyObject * cr_getframe(PyObject *coro, void *Py_UNUSED(ignored)) { @@ -1181,12 +1239,12 @@ static PyGetSetDef coro_getsetlist[] = { PyDoc_STR("name of the coroutine")}, {"__qualname__", gen_get_qualname, gen_set_qualname, PyDoc_STR("qualified name of the coroutine")}, - {"cr_await", coro_get_cr_await, NULL, + {"cr_await", gen_getyieldfrom, NULL, PyDoc_STR("object being awaited on, or None")}, - {"cr_running", cr_getrunning, NULL, NULL}, + {"cr_running", gen_getrunning, NULL, NULL}, {"cr_frame", cr_getframe, NULL, NULL}, {"cr_code", cr_getcode, NULL, NULL}, - {"cr_suspended", cr_getsuspended, NULL, NULL}, + {"cr_suspended", gen_getsuspended, NULL, NULL}, {NULL} /* Sentinel */ }; @@ -1602,26 +1660,16 @@ ag_getcode(PyObject *gen, void *Py_UNUSED(ignored)) return _gen_getcode((PyGenObject*)gen, "ag_code"); } -static PyObject * -ag_getsuspended(PyObject *self, void *Py_UNUSED(ignored)) -{ - PyAsyncGenObject *ag = _PyAsyncGenObject_CAST(self); - if (FRAME_STATE_SUSPENDED(ag->ag_frame_state)) { - Py_RETURN_TRUE; - } - Py_RETURN_FALSE; -} - static PyGetSetDef async_gen_getsetlist[] = { {"__name__", gen_get_name, gen_set_name, PyDoc_STR("name of the async generator")}, {"__qualname__", gen_get_qualname, gen_set_qualname, PyDoc_STR("qualified name of the async generator")}, - {"ag_await", coro_get_cr_await, NULL, + {"ag_await", gen_getyieldfrom, NULL, PyDoc_STR("object being awaited on, or None")}, {"ag_frame", ag_getframe, NULL, NULL}, {"ag_code", ag_getcode, NULL, NULL}, - {"ag_suspended", ag_getsuspended, NULL, NULL}, + {"ag_suspended", gen_getsuspended, NULL, NULL}, {NULL} /* Sentinel */ }; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1291fe56a59d5b..f7eb006e686800 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1312,14 +1312,13 @@ dummy_func( assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); if ((tstate->interp->eval_frame == NULL) && (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && - ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) + gen_try_set_executing((PyGenObject *)receiver_o)) { PyGenObject *gen = (PyGenObject *)receiver_o; _PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v)); DEAD(v); SYNC_SP(); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; assert(INSTRUCTION_SIZE + oparg <= UINT16_MAX); @@ -1360,12 +1359,11 @@ dummy_func( op(_SEND_GEN_FRAME, (receiver, v -- receiver, gen_frame)) { PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(receiver); DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type); - DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); + DEOPT_IF(!gen_try_set_executing((PyGenObject *)gen)); STAT_INC(SEND, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_MakeHeapSafe(v)); DEAD(v); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; assert(INSTRUCTION_SIZE + oparg <= UINT16_MAX); @@ -1389,7 +1387,6 @@ dummy_func( PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); - gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; DEAD(retval); SAVE_STACK(); @@ -1399,6 +1396,8 @@ dummy_func( _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); /* We don't know which of these is relevant here, so keep them equal */ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); #if TIER_ONE @@ -3405,18 +3404,10 @@ dummy_func( op(_FOR_ITER_GEN_FRAME, (iter, null -- iter, null, gen_frame)) { PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); DEOPT_IF(Py_TYPE(gen) != &PyGen_Type); -#ifdef Py_GIL_DISABLED - // Since generators can't be used by multiple threads anyway we - // don't need to deopt here, but this lets us work on making - // generators thread-safe without necessarily having to - // specialize them thread-safely as well. - DEOPT_IF(!_PyObject_IsUniquelyReferenced((PyObject *)gen)); -#endif - DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); + DEOPT_IF(!gen_try_set_executing((PyGenObject *)gen)); STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_None); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; pushed_frame->previous = frame; diff --git a/Python/ceval.c b/Python/ceval.c index cf86d5484f0d6e..ec21d6bc2b852c 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2304,7 +2304,8 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(frame->owner == FRAME_OWNED_BY_GENERATOR); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - gen->gi_frame_state = FRAME_CLEARED; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_CLEARED); + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_RETURN; assert(tstate->exc_info == &gen->gi_exc_state); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; @@ -3979,15 +3980,13 @@ _PyEval_GetAwaitable(PyObject *iterable, int oparg) Py_TYPE(iterable), oparg); } else if (PyCoro_CheckExact(iter)) { - PyObject *yf = _PyGen_yf((PyGenObject*)iter); - if (yf != NULL) { - /* `iter` is a coroutine object that is being - awaited, `yf` is a pointer to the current awaitable - being awaited on. */ - Py_DECREF(yf); + PyCoroObject *coro = (PyCoroObject *)iter; + int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(coro->cr_frame_state); + if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { + /* `iter` is a coroutine object that is being awaited. */ Py_CLEAR(iter); _PyErr_SetString(PyThreadState_GET(), PyExc_RuntimeError, - "coroutine is being awaited already"); + "coroutine is being awaited already"); } } return iter; diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index a526a453dd918a..c9472ec16d423e 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -496,3 +496,28 @@ check_periodics(PyThreadState *tstate) { return 0; } +// Mark the generator as executing. Returns true if the state was changed, +// false if it was already executing or finished. +static inline bool +gen_try_set_executing(PyGenObject *gen) +{ +#ifdef Py_GIL_DISABLED + if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { + int8_t frame_state = _Py_atomic_load_int8_relaxed(&gen->gi_frame_state); + while (frame_state < FRAME_EXECUTING) { + if (_Py_atomic_compare_exchange_int8(&gen->gi_frame_state, + &frame_state, + FRAME_EXECUTING)) { + return true; + } + } + } +#endif + // Use faster non-atomic modifications in the GIL-enabled build and when + // the object is uniquely referenced in the free-threaded build. + if (gen->gi_frame_state < FRAME_EXECUTING) { + gen->gi_frame_state = FRAME_EXECUTING; + return true; + } + return false; +} diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 2305df6ad5aaf1..b3eff63b30ab55 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5823,7 +5823,7 @@ SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } - if (gen->gi_frame_state >= FRAME_EXECUTING) { + if (!gen_try_set_executing((PyGenObject *)gen)) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = v; _tos_cache0 = receiver; @@ -5833,7 +5833,6 @@ STAT_INC(SEND, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_MakeHeapSafe(v)); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; assert( 2u + oparg <= UINT16_MAX); @@ -5861,7 +5860,6 @@ PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); - gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; _PyFrame_SetStackPointer(frame, stack_pointer); tstate->exc_info = gen->gi_exc_state.previous_item; @@ -5870,6 +5868,8 @@ _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 || @@ -10859,34 +10859,99 @@ break; } - case _FOR_ITER_GEN_FRAME_r23: { - CHECK_CURRENT_CACHED_VALUES(2); + case _FOR_ITER_GEN_FRAME_r03: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef gen_frame; + oparg = CURRENT_OPARG(); + iter = stack_pointer[-2]; + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(gen) != &PyGen_Type) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + if (!gen_try_set_executing((PyGenObject *)gen)) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(FOR_ITER, hit); + _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; + _PyFrame_StackPush(pushed_frame, PyStackRef_None); + gen->gi_exc_state.previous_item = tstate->exc_info; + tstate->exc_info = &gen->gi_exc_state; + pushed_frame->previous = frame; + frame->return_offset = (uint16_t)( 2u + oparg); + gen_frame = PyStackRef_Wrap(pushed_frame); + _tos_cache2 = gen_frame; + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _FOR_ITER_GEN_FRAME_r13: { + CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef iter; _PyStackRef gen_frame; _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); - iter = _stack_item_0; + iter = stack_pointer[-1]; PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); if (Py_TYPE(gen) != &PyGen_Type) { UOP_STAT_INC(uopcode, miss); - _tos_cache1 = _stack_item_1; - _tos_cache0 = iter; - SET_CURRENT_CACHED_VALUES(2); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } - #ifdef Py_GIL_DISABLED + if (!gen_try_set_executing((PyGenObject *)gen)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + STAT_INC(FOR_ITER, hit); + _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; + _PyFrame_StackPush(pushed_frame, PyStackRef_None); + gen->gi_exc_state.previous_item = tstate->exc_info; + tstate->exc_info = &gen->gi_exc_state; + pushed_frame->previous = frame; + frame->return_offset = (uint16_t)( 2u + oparg); + gen_frame = PyStackRef_Wrap(pushed_frame); + _tos_cache2 = gen_frame; + _tos_cache1 = _stack_item_0; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } - if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { + case _FOR_ITER_GEN_FRAME_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef gen_frame; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + iter = _stack_item_0; + PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(gen) != &PyGen_Type) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; _tos_cache0 = iter; SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } - #endif - if (gen->gi_frame_state >= FRAME_EXECUTING) { + if (!gen_try_set_executing((PyGenObject *)gen)) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; _tos_cache0 = iter; @@ -10896,7 +10961,6 @@ STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_None); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; pushed_frame->previous = frame; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 4482bb08a132f9..eaaa5f3bb96abc 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5548,14 +5548,7 @@ assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); } - #ifdef Py_GIL_DISABLED - if (!_PyObject_IsUniquelyReferenced((PyObject *)gen)) { - UPDATE_MISS_STATS(FOR_ITER); - assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); - JUMP_TO_PREDICTED(FOR_ITER); - } - #endif - if (gen->gi_frame_state >= FRAME_EXECUTING) { + if (!gen_try_set_executing((PyGenObject *)gen)) { UPDATE_MISS_STATS(FOR_ITER); assert(_PyOpcode_Deopt[opcode] == (FOR_ITER)); JUMP_TO_PREDICTED(FOR_ITER); @@ -5563,7 +5556,6 @@ STAT_INC(FOR_ITER, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_None); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; pushed_frame->previous = frame; @@ -7327,7 +7319,6 @@ PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); - gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -7338,6 +7329,8 @@ _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 || @@ -10301,14 +10294,13 @@ assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); if ((tstate->interp->eval_frame == NULL) && (Py_TYPE(receiver_o) == &PyGen_Type || Py_TYPE(receiver_o) == &PyCoro_Type) && - ((PyGenObject *)receiver_o)->gi_frame_state < FRAME_EXECUTING) + gen_try_set_executing((PyGenObject *)receiver_o)) { PyGenObject *gen = (PyGenObject *)receiver_o; _PyInterpreterFrame *gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, PyStackRef_MakeHeapSafe(v)); stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; assert( 2u + oparg <= UINT16_MAX); @@ -10401,7 +10393,7 @@ assert(_PyOpcode_Deopt[opcode] == (SEND)); JUMP_TO_PREDICTED(SEND); } - if (gen->gi_frame_state >= FRAME_EXECUTING) { + if (!gen_try_set_executing((PyGenObject *)gen)) { UPDATE_MISS_STATS(SEND); assert(_PyOpcode_Deopt[opcode] == (SEND)); JUMP_TO_PREDICTED(SEND); @@ -10409,7 +10401,6 @@ STAT_INC(SEND, hit); _PyInterpreterFrame *pushed_frame = &gen->gi_iframe; _PyFrame_StackPush(pushed_frame, PyStackRef_MakeHeapSafe(v)); - gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; assert( 2u + oparg <= UINT16_MAX); @@ -12045,7 +12036,6 @@ PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); - gen->gi_frame_state = FRAME_SUSPENDED + oparg; _PyStackRef temp = retval; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -12056,6 +12046,8 @@ _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 || diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index fcd0dcf12acb2b..659befe312afaf 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -642,6 +642,7 @@ def has_error_without_pop(op: parser.CodeDef) -> bool: "_PyFrame_StackPush", "_PyFunction_SetVersion", "_PyGen_GetGeneratorFromFrame", + "gen_try_set_executing", "_PyInterpreterState_GET", "_PyList_AppendTakeRef", "_PyList_ITEMS", From 4ea3c1a04747978361b497798428423cbb6a7146 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 19 Dec 2025 17:33:49 -0500 Subject: [PATCH 027/105] gh-120321: Fix TSan reported race in gen_clear_frame (gh-142995) TSan treats compare-exchanges that fail as if they are writes so there is a false positive with the read of gi_frame_state in gen_close. --- Objects/genobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index 508d215a0cfe64..1e59d89f5ce85f 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -153,7 +153,7 @@ _PyGen_Finalize(PyObject *self) static void gen_clear_frame(PyGenObject *gen) { - assert(gen->gi_frame_state == FRAME_CLEARED); + assert(FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state) == FRAME_CLEARED); _PyInterpreterFrame *frame = &gen->gi_iframe; frame->previous = NULL; _PyFrame_ClearExceptCode(frame); From e46f28c6afce9c85e4bc4a113d1c7efc472e7d8f Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 19 Dec 2025 18:06:47 -0500 Subject: [PATCH 028/105] gh-129069: Fix listobject.c data races due to memmove (gh-142957) The use of memmove and _Py_memory_repeat were not thread-safe in the free threading build in some cases. In theory, memmove and _Py_memory_repeat can copy byte-by-byte instead of pointer-by-pointer, so concurrent readers could see uninitialized data or tearing. Additionally, we should be using "release" (or stronger) ordering to be compliant with the C11 memory model when copying objects within a list. --- Objects/listobject.c | 103 +++++++++++++-------- Tools/tsan/suppressions_free_threading.txt | 6 -- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 1722ea60cdc68f..f67d1a45a494cb 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -96,11 +96,7 @@ ensure_shared_on_resize(PyListObject *self) * of the new slots at exit is undefined heap trash; it's the caller's * responsibility to overwrite them with sane values. * The number of allocated elements may grow, shrink, or stay the same. - * Failure is impossible if newsize <= self.allocated on entry, although - * that partly relies on an assumption that the system realloc() never - * fails when passed a number of bytes <= the number of bytes last - * allocated (the C standard doesn't guarantee this, but it's hard to - * imagine a realloc implementation where it wouldn't be true). + * Failure is impossible if newsize <= self.allocated on entry. * Note that self->ob_item may change, and even if newsize is less * than ob_size on entry. */ @@ -145,6 +141,11 @@ list_resize(PyListObject *self, Py_ssize_t newsize) #ifdef Py_GIL_DISABLED _PyListArray *array = list_allocate_array(new_allocated); if (array == NULL) { + if (newsize < allocated) { + // Never fail when shrinking allocations + Py_SET_SIZE(self, newsize); + return 0; + } PyErr_NoMemory(); return -1; } @@ -178,6 +179,11 @@ list_resize(PyListObject *self, Py_ssize_t newsize) items = NULL; } if (items == NULL) { + if (newsize < allocated) { + // Never fail when shrinking allocations + Py_SET_SIZE(self, newsize); + return 0; + } PyErr_NoMemory(); return -1; } @@ -818,8 +824,8 @@ list_repeat_lock_held(PyListObject *a, Py_ssize_t n) _Py_RefcntAdd(*src, n); *dest++ = *src++; } - // TODO: _Py_memory_repeat calls are not safe for shared lists in - // GIL_DISABLED builds. (See issue #129069) + // This list is not yet visible to other threads, so atomic repeat + // is not necessary even in Py_GIL_DISABLED builds. _Py_memory_repeat((char *)np->ob_item, sizeof(PyObject *)*output_size, sizeof(PyObject *)*input_size); } @@ -882,6 +888,34 @@ list_clear_slot(PyObject *self) return 0; } +// Pointer-by-pointer memmove for PyObject** arrays that is safe +// for shared lists in Py_GIL_DISABLED builds. +static void +ptr_wise_atomic_memmove(PyListObject *a, PyObject **dest, PyObject **src, Py_ssize_t n) +{ +#ifndef Py_GIL_DISABLED + memmove(dest, src, n * sizeof(PyObject *)); +#else + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(a); + if (_Py_IsOwnedByCurrentThread((PyObject *)a) && !_PyObject_GC_IS_SHARED(a)) { + // No other threads can read this list concurrently + memmove(dest, src, n * sizeof(PyObject *)); + return; + } + if (dest < src) { + for (Py_ssize_t i = 0; i != n; i++) { + _Py_atomic_store_ptr_release(&dest[i], src[i]); + } + } + else { + // copy backwards to avoid overwriting src before it's read + for (Py_ssize_t i = n; i != 0; i--) { + _Py_atomic_store_ptr_release(&dest[i - 1], src[i - 1]); + } + } +#endif +} + /* a[ilow:ihigh] = v if v != NULL. * del a[ilow:ihigh] if v == NULL. * @@ -952,16 +986,9 @@ list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyO } if (d < 0) { /* Delete -d items */ - Py_ssize_t tail; - tail = (Py_SIZE(a) - ihigh) * sizeof(PyObject *); - // TODO: these memmove/memcpy calls are not safe for shared lists in - // GIL_DISABLED builds. (See issue #129069) - memmove(&item[ihigh+d], &item[ihigh], tail); - if (list_resize(a, Py_SIZE(a) + d) < 0) { - memmove(&item[ihigh], &item[ihigh+d], tail); - memcpy(&item[ilow], recycle, s); - goto Error; - } + Py_ssize_t tail = Py_SIZE(a) - ihigh; + ptr_wise_atomic_memmove(a, &item[ihigh+d], &item[ihigh], tail); + (void)list_resize(a, Py_SIZE(a) + d); // NB: shrinking a list can't fail item = a->ob_item; } else if (d > 0) { /* Insert d items */ @@ -969,10 +996,7 @@ list_ass_slice_lock_held(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyO if (list_resize(a, k+d) < 0) goto Error; item = a->ob_item; - // TODO: these memmove/memcpy calls are not safe for shared lists in - // GIL_DISABLED builds. (See issue #129069) - memmove(&item[ihigh+d], &item[ihigh], - (k - ihigh)*sizeof(PyObject *)); + ptr_wise_atomic_memmove(a, &item[ihigh+d], &item[ihigh], k - ihigh); } for (k = 0; k < n; k++, ilow++) { PyObject *w = vitem[k]; @@ -1056,10 +1080,17 @@ list_inplace_repeat_lock_held(PyListObject *self, Py_ssize_t n) for (Py_ssize_t j = 0; j < input_size; j++) { _Py_RefcntAdd(items[j], n-1); } - // TODO: _Py_memory_repeat calls are not safe for shared lists in - // GIL_DISABLED builds. (See issue #129069) +#ifndef Py_GIL_DISABLED _Py_memory_repeat((char *)items, sizeof(PyObject *)*output_size, sizeof(PyObject *)*input_size); +#else + Py_ssize_t copied = input_size; + while (copied < output_size) { + Py_ssize_t items_to_copy = Py_MIN(copied, output_size - copied); + ptr_wise_atomic_memmove(self, items + copied, items, items_to_copy); + copied += items_to_copy; + } +#endif return 0; } @@ -1532,7 +1563,6 @@ list_pop_impl(PyListObject *self, Py_ssize_t index) /*[clinic end generated code: output=6bd69dcb3f17eca8 input=c269141068ae4b8f]*/ { PyObject *v; - int status; if (Py_SIZE(self) == 0) { /* Special-case most common failure cause */ @@ -1548,27 +1578,18 @@ list_pop_impl(PyListObject *self, Py_ssize_t index) PyObject **items = self->ob_item; v = items[index]; - const Py_ssize_t size_after_pop = Py_SIZE(self) - 1; - if (size_after_pop == 0) { + if (Py_SIZE(self) == 1) { Py_INCREF(v); list_clear(self); - status = 0; - } - else { - if ((size_after_pop - index) > 0) { - memmove(&items[index], &items[index+1], (size_after_pop - index) * sizeof(PyObject *)); - } - status = list_resize(self, size_after_pop); + return v; } - if (status >= 0) { - return v; // and v now owns the reference the list had - } - else { - // list resize failed, need to restore - memmove(&items[index+1], &items[index], (size_after_pop - index)* sizeof(PyObject *)); - items[index] = v; - return NULL; + Py_ssize_t size_after_pop = Py_SIZE(self) - 1; + if (index < size_after_pop) { + ptr_wise_atomic_memmove(self, &items[index], &items[index+1], + size_after_pop - index); } + list_resize(self, size_after_pop); // NB: shrinking a list can't fail + return v; } /* Reverse a slice of a list in place, from lo up to (exclusive) hi. */ diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index adc85d631db7c6..e8b1501c34bfc1 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -23,12 +23,6 @@ race_top:write_thread_id # https://gist.github.com/mpage/6962e8870606cfc960e159b407a0cb40 thread:pthread_create -# List resizing happens through different paths ending in memcpy or memmove -# (for efficiency), which will probably need to rewritten as explicit loops -# of ptr-sized copies to be thread-safe. (Issue #129069) -race:list_ass_slice_lock_held -race:list_inplace_repeat_lock_held - # PyObject_Realloc internally does memcpy which isn't atomic so can race # with non-locking reads. See #132070 race:PyObject_Realloc From 5b5263648f2404b22f9a596c67350c2e602df52b Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Sat, 20 Dec 2025 03:36:09 +0200 Subject: [PATCH 029/105] gh-142927: Tachyon: Start with user's default light/dark theme (#142987) --- .../sampling/_heatmap_assets/heatmap.js | 26 +------------- .../sampling/_heatmap_assets/heatmap_index.js | 27 +------------- .../heatmap_index_template.html | 2 +- .../heatmap_pyfile_template.html | 2 +- .../_heatmap_assets/heatmap_shared.js | 36 +++++++++++++++++++ 5 files changed, 40 insertions(+), 53 deletions(-) diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js index d6a91ef290309b..90b5b111d36a8f 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -15,37 +15,13 @@ let coldCodeHidden = false; // ============================================================================ function toggleTheme() { - const html = document.documentElement; - const current = html.getAttribute('data-theme') || 'light'; - const next = current === 'light' ? 'dark' : 'light'; - html.setAttribute('data-theme', next); - localStorage.setItem('heatmap-theme', next); - - // Update theme button icon - const btn = document.getElementById('theme-btn'); - if (btn) { - btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : ''; - btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 'none'; - } + toggleAndSaveTheme(); applyLineColors(); // Rebuild scroll marker with new theme colors buildScrollMarker(); } -function restoreUIState() { - // Restore theme - const savedTheme = localStorage.getItem('heatmap-theme'); - if (savedTheme) { - document.documentElement.setAttribute('data-theme', savedTheme); - const btn = document.getElementById('theme-btn'); - if (btn) { - btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 'none' : ''; - btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? '' : 'none'; - } - } -} - // ============================================================================ // Utility Functions // ============================================================================ diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js b/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js index 8eb6af0db5335e..db4b5485056217 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_index.js @@ -19,35 +19,10 @@ function applyHeatmapBarColors() { // ============================================================================ function toggleTheme() { - const html = document.documentElement; - const current = html.getAttribute('data-theme') || 'light'; - const next = current === 'light' ? 'dark' : 'light'; - html.setAttribute('data-theme', next); - localStorage.setItem('heatmap-theme', next); - - // Update theme button icon - const btn = document.getElementById('theme-btn'); - if (btn) { - btn.querySelector('.icon-moon').style.display = next === 'dark' ? 'none' : ''; - btn.querySelector('.icon-sun').style.display = next === 'dark' ? '' : 'none'; - } - + toggleAndSaveTheme(); applyHeatmapBarColors(); } -function restoreUIState() { - // Restore theme - const savedTheme = localStorage.getItem('heatmap-theme'); - if (savedTheme) { - document.documentElement.setAttribute('data-theme', savedTheme); - const btn = document.getElementById('theme-btn'); - if (btn) { - btn.querySelector('.icon-moon').style.display = savedTheme === 'dark' ? 'none' : ''; - btn.querySelector('.icon-sun').style.display = savedTheme === 'dark' ? '' : 'none'; - } - } -} - // ============================================================================ // Type Section Toggle (stdlib, project, etc) // ============================================================================ diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html b/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html index 3620f8efb8058a..8d04149abe3014 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_index_template.html @@ -1,5 +1,5 @@ - + diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html b/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html index 91b629b2628244..2a9c07647e64cd 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_pyfile_template.html @@ -1,5 +1,5 @@ - + diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js index 7fcd720d45d7b3..84b13ca0a9682b 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap_shared.js @@ -39,6 +39,42 @@ function intensityToColor(intensity) { return rootStyle.getPropertyValue(`--heat-${level}`).trim(); } +// ============================================================================ +// Theme Support +// ============================================================================ + +// Get the preferred theme from localStorage or browser preference +function getPreferredTheme() { + const saved = localStorage.getItem('heatmap-theme'); + if (saved) return saved; + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; +} + +// Apply theme and update UI. Returns the applied theme. +function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + const btn = document.getElementById('theme-btn'); + if (btn) { + btn.querySelector('.icon-moon').style.display = theme === 'dark' ? 'none' : ''; + btn.querySelector('.icon-sun').style.display = theme === 'dark' ? '' : 'none'; + } + return theme; +} + +// Toggle theme and save preference. Returns the new theme. +function toggleAndSaveTheme() { + const current = document.documentElement.getAttribute('data-theme') || 'light'; + const next = current === 'light' ? 'dark' : 'light'; + applyTheme(next); + localStorage.setItem('heatmap-theme', next); + return next; +} + +// Restore theme from localStorage, or use browser preference +function restoreUIState() { + applyTheme(getPreferredTheme()); +} + // ============================================================================ // Favicon (Reuse logo image as favicon) // ============================================================================ From 5989095dfd08735525f2b615066bc3c231b09388 Mon Sep 17 00:00:00 2001 From: AZero13 Date: Sat, 20 Dec 2025 02:37:10 -0500 Subject: [PATCH 030/105] gh-143012: use `Py_ssize_t` cast for `PyBytes_FromStringAndSize` (#143013) --- Modules/posixmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 221cfc5a934198..e0276ce9e3906f 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1815,7 +1815,7 @@ convertenviron(void) #ifdef MS_WINDOWS k = PyUnicode_FromWideChar(*e, (Py_ssize_t)(p-*e)); #else - k = PyBytes_FromStringAndSize(*e, (int)(p-*e)); + k = PyBytes_FromStringAndSize(*e, (Py_ssize_t)(p-*e)); #endif if (k == NULL) { Py_DECREF(d); From 3cc57505e530c64b7d783e5ac15d3e66d233bbbb Mon Sep 17 00:00:00 2001 From: Hai Zhu <35182391+cocolato@users.noreply.github.com> Date: Sun, 21 Dec 2025 01:27:34 +0800 Subject: [PATCH 031/105] gh-142834: pdb commands command should use last available breakpoint (#142835) --- Doc/library/pdb.rst | 3 +- Lib/pdb.py | 9 +++- Lib/test/test_pdb.py | 43 +++++++++++++++++++ ...-12-16-15-32-41.gh-issue-142834.g7mHw_.rst | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-16-15-32-41.gh-issue-142834.g7mHw_.rst diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index 0bbdc42535290a..8ab3e7ec9ef9d2 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -520,7 +520,8 @@ can be overridden by the local file. To remove all commands from a breakpoint, type ``commands`` and follow it immediately with ``end``; that is, give no commands. - With no *bpnumber* argument, ``commands`` refers to the last breakpoint set. + With no *bpnumber* argument, ``commands`` refers to the most recently set + breakpoint that still exists. You can use breakpoint commands to start your program up again. Simply use the :pdbcmd:`continue` command, or :pdbcmd:`step`, diff --git a/Lib/pdb.py b/Lib/pdb.py index c1a5db080dc7ef..4a6bc17e91cf0c 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -1315,7 +1315,14 @@ def do_commands(self, arg): reached. """ if not arg: - bnum = len(bdb.Breakpoint.bpbynumber) - 1 + for bp in reversed(bdb.Breakpoint.bpbynumber): + if bp is None: + continue + bnum = bp.number + break + else: + self.error('cannot set commands: no existing breakpoint') + return else: try: bnum = int(arg) diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 5cba34ff8bad10..4352aa6abfeabb 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -3478,6 +3478,49 @@ def test_pdb_issue_gh_65052(): (Pdb) continue """ +def test_pdb_commands_last_breakpoint(): + """See GH-142834 + + >>> def test_function(): + ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + ... foo = 1 + ... bar = 2 + + >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE + ... 'break 4', + ... 'break 3', + ... 'clear 2', + ... 'commands', + ... 'p "success"', + ... 'end', + ... 'continue', + ... 'clear 1', + ... 'commands', + ... 'continue', + ... ]): + ... test_function() + > (2)test_function() + -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace() + (Pdb) break 4 + Breakpoint 1 at :4 + (Pdb) break 3 + Breakpoint 2 at :3 + (Pdb) clear 2 + Deleted breakpoint 2 at :3 + (Pdb) commands + (com) p "success" + (com) end + (Pdb) continue + 'success' + > (4)test_function() + -> bar = 2 + (Pdb) clear 1 + Deleted breakpoint 1 at :4 + (Pdb) commands + *** cannot set commands: no existing breakpoint + (Pdb) continue + """ + @support.force_not_colorized_test_class @support.requires_subprocess() diff --git a/Misc/NEWS.d/next/Library/2025-12-16-15-32-41.gh-issue-142834.g7mHw_.rst b/Misc/NEWS.d/next/Library/2025-12-16-15-32-41.gh-issue-142834.g7mHw_.rst new file mode 100644 index 00000000000000..8cde592e7c937d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-16-15-32-41.gh-issue-142834.g7mHw_.rst @@ -0,0 +1 @@ +Change the :mod:`pdb` ``commands`` command to use the last available breakpoint instead of failing when the most recently created breakpoint was deleted. From 7607712b61b7ab35c08e189155c0e161f9ad74b0 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Sat, 20 Dec 2025 14:42:12 -0500 Subject: [PATCH 032/105] gh-120321: Avoid `-Wunreachable-code` warning on Clang (gh-143022) --- Objects/genobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index 1e59d89f5ce85f..020af903a3f828 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -422,7 +422,8 @@ gen_close(PyObject *self, PyObject *args) int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); do { if (frame_state == FRAME_CREATED) { - if (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_CLEARED)) { + // && (1) to avoid -Wunreachable-code warning on Clang + if (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_CLEARED) && (1)) { continue; } gen_clear_frame(gen); From 2b4feee648b7af0ccca8dee167fdd21cfb0bd23a Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Sat, 20 Dec 2025 15:37:31 -0500 Subject: [PATCH 033/105] gh-122581: Use parser mutex in default build for subinterpreters (gh-142959) --- Include/internal/pycore_parser.h | 16 ---------------- Include/internal/pycore_runtime_structs.h | 2 -- Parser/pegen.c | 19 +++++++++---------- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/Include/internal/pycore_parser.h b/Include/internal/pycore_parser.h index 2c46f59ab7da9f..b89d02035db71f 100644 --- a/Include/internal/pycore_parser.h +++ b/Include/internal/pycore_parser.h @@ -14,10 +14,8 @@ extern "C" { #include "pycore_pyarena.h" // PyArena _Py_DECLARE_STR(empty, "") -#if defined(Py_DEBUG) && defined(Py_GIL_DISABLED) #define _parser_runtime_state_INIT \ { \ - .mutex = {0}, \ .dummy_name = { \ .kind = Name_kind, \ .v.Name.id = &_Py_STR(empty), \ @@ -28,20 +26,6 @@ _Py_DECLARE_STR(empty, "") .end_col_offset = 0, \ }, \ } -#else -#define _parser_runtime_state_INIT \ - { \ - .dummy_name = { \ - .kind = Name_kind, \ - .v.Name.id = &_Py_STR(empty), \ - .v.Name.ctx = Load, \ - .lineno = 1, \ - .col_offset = 0, \ - .end_lineno = 1, \ - .end_col_offset = 0, \ - }, \ - } -#endif extern struct _mod* _PyParser_ASTFromString( const char *str, diff --git a/Include/internal/pycore_runtime_structs.h b/Include/internal/pycore_runtime_structs.h index 995f49e78dcda3..92387031ad7465 100644 --- a/Include/internal/pycore_runtime_structs.h +++ b/Include/internal/pycore_runtime_structs.h @@ -77,9 +77,7 @@ struct _fileutils_state { struct _parser_runtime_state { #ifdef Py_DEBUG long memo_statistics[_PYPEGEN_NSTATISTICS]; -#ifdef Py_GIL_DISABLED PyMutex mutex; -#endif #else int _not_used; #endif diff --git a/Parser/pegen.c b/Parser/pegen.c index a38e973b3f64c6..7ecc55eee13775 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -3,9 +3,8 @@ #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_parser.h" // _PYPEGEN_NSTATISTICS #include "pycore_pyerrors.h" // PyExc_IncompleteInputError -#include "pycore_runtime.h" // _PyRuntime +#include "pycore_runtime.h" // _PyRuntime #include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal -#include "pycore_pyatomic_ft_wrappers.h" #include #include "lexer/lexer.h" @@ -303,11 +302,11 @@ _PyPegen_fill_token(Parser *p) void _PyPegen_clear_memo_statistics(void) { - FT_MUTEX_LOCK(&_PyRuntime.parser.mutex); + PyMutex_Lock(&_PyRuntime.parser.mutex); for (int i = 0; i < NSTATISTICS; i++) { memo_statistics[i] = 0; } - FT_MUTEX_UNLOCK(&_PyRuntime.parser.mutex); + PyMutex_Unlock(&_PyRuntime.parser.mutex); } PyObject * @@ -318,22 +317,22 @@ _PyPegen_get_memo_statistics(void) return NULL; } - FT_MUTEX_LOCK(&_PyRuntime.parser.mutex); + PyMutex_Lock(&_PyRuntime.parser.mutex); for (int i = 0; i < NSTATISTICS; i++) { PyObject *value = PyLong_FromLong(memo_statistics[i]); if (value == NULL) { - FT_MUTEX_UNLOCK(&_PyRuntime.parser.mutex); + PyMutex_Unlock(&_PyRuntime.parser.mutex); Py_DECREF(ret); return NULL; } // PyList_SetItem borrows a reference to value. if (PyList_SetItem(ret, i, value) < 0) { - FT_MUTEX_UNLOCK(&_PyRuntime.parser.mutex); + PyMutex_Unlock(&_PyRuntime.parser.mutex); Py_DECREF(ret); return NULL; } } - FT_MUTEX_UNLOCK(&_PyRuntime.parser.mutex); + PyMutex_Unlock(&_PyRuntime.parser.mutex); return ret; } #endif @@ -359,9 +358,9 @@ _PyPegen_is_memoized(Parser *p, int type, void *pres) if (count <= 0) { count = 1; } - FT_MUTEX_LOCK(&_PyRuntime.parser.mutex); + PyMutex_Lock(&_PyRuntime.parser.mutex); memo_statistics[type] += count; - FT_MUTEX_UNLOCK(&_PyRuntime.parser.mutex); + PyMutex_Unlock(&_PyRuntime.parser.mutex); } #endif p->mark = m->mark; From 8d2d7bb2e754f8649a68ce4116271a4932f76907 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> Date: Sat, 20 Dec 2025 15:42:06 -0800 Subject: [PATCH 034/105] gh-142145: relax the no-longer-quadratic test timing (#143030) * gh-142145: relax the no-longer-quadratic test timing * require cpu resource --- Lib/test/test_minidom.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py index 7717a98583f741..69fae957ec7fc9 100644 --- a/Lib/test/test_minidom.py +++ b/Lib/test/test_minidom.py @@ -174,6 +174,7 @@ def testAppendChild(self): self.assertEqual(dom.documentElement.childNodes[-1].data, "Hello") dom.unlink() + @support.requires_resource('cpu') def testAppendChildNoQuadraticComplexity(self): impl = getDOMImplementation() @@ -182,14 +183,18 @@ def testAppendChildNoQuadraticComplexity(self): children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)] element = top_element - start = time.time() + start = time.monotonic() for child in children: element.appendChild(child) element = child - end = time.time() + end = time.monotonic() # This example used to take at least 30 seconds. - self.assertLess(end - start, 1) + # Conservative assertion due to the wide variety of systems and + # build configs timing based tests wind up run under. + # A --with-address-sanitizer --with-pydebug build on a rpi5 still + # completes this loop in <0.5 seconds. + self.assertLess(end - start, 4) def testSetAttributeNodeWithoutOwnerDocument(self): # regression test for gh-142754 From b8d3fddba6e96e693ced0d3b8f6ddbd61428fd32 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> Date: Sat, 20 Dec 2025 22:47:40 -0800 Subject: [PATCH 035/105] gh-70647: Better promote how to safely parse yearless dates in datetime. (GH-116179) * gh-70647: Better promote how to safely parse yearless dates in datetime. Every four years people encounter this because it just isn't obvious. This moves the footnote up to a note with a code example. We'd love to change the default year value for datetime but doing that could have other consequences for existing code. This documented workaround *always* works. * doctest code within note is bad, dedent. * Update to match the error message. * remove no longer referenced footnote * ignore the warning in the doctest * use Petr's suggestion for the docs to hide the warning processing * cover date.strptime (3.14) as well --- Doc/library/datetime.rst | 43 ++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst index 8ae1c1fb9e46bb..48e7080da6c525 100644 --- a/Doc/library/datetime.rst +++ b/Doc/library/datetime.rst @@ -2651,9 +2651,42 @@ Broadly speaking, ``d.strftime(fmt)`` acts like the :mod:`time` module's ``time.strftime(fmt, d.timetuple())`` although not all objects support a :meth:`~date.timetuple` method. -For the :meth:`.datetime.strptime` class method, the default value is -``1900-01-01T00:00:00.000``: any components not specified in the format string -will be pulled from the default value. [#]_ +For the :meth:`.datetime.strptime` and :meth:`.date.strptime` class methods, +the default value is ``1900-01-01T00:00:00.000``: any components not specified +in the format string will be pulled from the default value. + +.. note:: + When used to parse partial dates lacking a year, :meth:`.datetime.strptime` + and :meth:`.date.strptime` will raise when encountering February 29 because + the default year of 1900 is *not* a leap year. Always add a default leap + year to partial date strings before parsing. + + +.. testsetup:: + + # doctest seems to turn the warning into an error which makes it + # show up and require matching and prevents the actual interesting + # exception from being raised. + # Manually apply the catch_warnings context manager + import warnings + catch_warnings = warnings.catch_warnings() + catch_warnings.__enter__() + warnings.simplefilter("ignore") + +.. testcleanup:: + + catch_warnings.__exit__() + +.. doctest:: + + >>> from datetime import datetime + >>> value = "2/29" + >>> datetime.strptime(value, "%m/%d") + Traceback (most recent call last): + ... + ValueError: day 29 must be in range 1..28 for month 2 in year 1900 + >>> datetime.strptime(f"1904 {value}", "%Y %m/%d") + datetime.datetime(1904, 2, 29, 0, 0) Using ``datetime.strptime(date_string, format)`` is equivalent to:: @@ -2790,7 +2823,7 @@ Notes: include a year in the format. If the value you need to parse lacks a year, append an explicit dummy leap year. Otherwise your code will raise an exception when it encounters leap day because the default year used by the - parser is not a leap year. Users run into this bug every four years... + parser (1900) is not a leap year. Users run into that bug every leap year. .. doctest:: @@ -2817,5 +2850,3 @@ Notes: .. [#] See R. H. van Gent's `guide to the mathematics of the ISO 8601 calendar `_ for a good explanation. - -.. [#] Passing ``datetime.strptime('Feb 29', '%b %d')`` will fail since 1900 is not a leap year. From 09044dd42b50e628b197afb2979afcbe49d4b83f Mon Sep 17 00:00:00 2001 From: saucoide <32314353+saucoide@users.noreply.github.com> Date: Sun, 21 Dec 2025 17:58:07 +0100 Subject: [PATCH 036/105] gh-80744: do not read .pdbrc twice when cwd == $home (#136816) --- Lib/pdb.py | 19 ++++++++++++------- Lib/test/test_pdb.py | 17 +++++++++++++++++ ...5-12-20-16-35-42.gh-issue-80744.X4pZ2N.rst | 1 + 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-20-16-35-42.gh-issue-80744.X4pZ2N.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 4a6bc17e91cf0c..eee0273fdc463f 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -391,17 +391,22 @@ def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None, # Read ~/.pdbrc and ./.pdbrc self.rcLines = [] if readrc: + home_rcfile = os.path.expanduser("~/.pdbrc") + local_rcfile = os.path.abspath(".pdbrc") + try: - with open(os.path.expanduser('~/.pdbrc'), encoding='utf-8') as rcFile: - self.rcLines.extend(rcFile) - except OSError: - pass - try: - with open(".pdbrc", encoding='utf-8') as rcFile: - self.rcLines.extend(rcFile) + with open(home_rcfile, encoding='utf-8') as rcfile: + self.rcLines.extend(rcfile) except OSError: pass + if local_rcfile != home_rcfile: + try: + with open(local_rcfile, encoding='utf-8') as rcfile: + self.rcLines.extend(rcfile) + except OSError: + pass + self.commands = {} # associates a command list to breakpoint numbers self.commands_defining = False # True while in the process of defining # a command list diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py index 4352aa6abfeabb..0e23cd6604379c 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py @@ -4093,6 +4093,23 @@ def test_readrc_homedir(self): f.write("invalid") self.assertEqual(pdb.Pdb().rcLines[0], "invalid") + def test_readrc_current_dir(self): + with os_helper.temp_cwd() as cwd: + rc_path = os.path.join(cwd, ".pdbrc") + with open(rc_path, "w") as f: + f.write("invalid") + self.assertEqual(pdb.Pdb().rcLines[-1], "invalid") + + def test_readrc_cwd_is_home(self): + with os_helper.EnvironmentVarGuard() as env: + env.unset("HOME") + with os_helper.temp_cwd() as cwd, patch("os.path.expanduser"): + rc_path = os.path.join(cwd, ".pdbrc") + os.path.expanduser.return_value = rc_path + with open(rc_path, "w") as f: + f.write("invalid") + self.assertEqual(pdb.Pdb().rcLines, ["invalid"]) + def test_header(self): stdout = StringIO() header = 'Nobody expects... blah, blah, blah' diff --git a/Misc/NEWS.d/next/Library/2025-12-20-16-35-42.gh-issue-80744.X4pZ2N.rst b/Misc/NEWS.d/next/Library/2025-12-20-16-35-42.gh-issue-80744.X4pZ2N.rst new file mode 100644 index 00000000000000..03ec9e4652b8cc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-20-16-35-42.gh-issue-80744.X4pZ2N.rst @@ -0,0 +1 @@ +Fix issue where ``pdb`` would read a ``.pdbrc`` twice if launched from the home directory From 6213a512bf42464e35ae5090358b80aaa64904cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Mon, 22 Dec 2025 08:05:15 +0100 Subject: [PATCH 037/105] gh-143046: Make asyncio REPL respect the `-q` flag (quiet mode) (#143047) --- Lib/asyncio/__main__.py | 17 +++++++++-------- Lib/test/test_repl.py | 6 ++++++ ...25-12-21-17-44-28.gh-issue-143046.GBa5Ip.rst | 2 ++ 3 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-21-17-44-28.gh-issue-143046.GBa5Ip.rst diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index 89d456b6858c07..afbb70bbcab930 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -86,14 +86,15 @@ def run(self): global return_code try: - banner = ( - f'asyncio REPL {sys.version} on {sys.platform}\n' - f'Use "await" directly instead of "asyncio.run()".\n' - f'Type "help", "copyright", "credits" or "license" ' - f'for more information.\n' - ) - - console.write(banner) + if not sys.flags.quiet: + banner = ( + f'asyncio REPL {sys.version} on {sys.platform}\n' + f'Use "await" directly instead of "asyncio.run()".\n' + f'Type "help", "copyright", "credits" or "license" ' + f'for more information.\n' + ) + + console.write(banner) if startup_path := os.getenv("PYTHONSTARTUP"): sys.audit("cpython.run_startup", startup_path) diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 042aa84b35dcf8..0fa1df40e44c5f 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -409,6 +409,12 @@ def test_toplevel_contextvars_async(self): expected = "toplevel contextvar test: ok" self.assertIn(expected, output, expected) + def test_quiet_mode(self): + p = spawn_repl("-q", "-m", "asyncio", custom=True) + output = kill_python(p) + self.assertEqual(p.returncode, 0) + self.assertEqual(output[:3], ">>>") + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2025-12-21-17-44-28.gh-issue-143046.GBa5Ip.rst b/Misc/NEWS.d/next/Library/2025-12-21-17-44-28.gh-issue-143046.GBa5Ip.rst new file mode 100644 index 00000000000000..ac819a47f4cde9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-21-17-44-28.gh-issue-143046.GBa5Ip.rst @@ -0,0 +1,2 @@ +The :mod:`asyncio` REPL no longer prints copyright and version messages in +the quiet mode (:option:`-q`). Patch by Bartosz Sławecki. From 39608781437e3ab9b3be88bfdb99ac0e4ac78576 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Mon, 22 Dec 2025 18:16:50 +0800 Subject: [PATCH 038/105] Remove unreachable code in mmapmodule error path on Windows (GH-143063) mmapmodule: remove unreachable code in Windows error path Remove an unreachable `return NULL` after `PyErr_SetFromWindowsErr()` in the Windows mmap resize error path. Signed-off-by: Yongtao Huang --- Modules/mmapmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index ea20fb29c90228..0928ea6a8b70ba 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -963,7 +963,6 @@ mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size) if (error) { return PyErr_SetFromWindowsErr(error); - return NULL; } /* It's possible for a resize to fail, typically because another mapping is still held against the same underlying file. Even if nothing has From ff7f62eb2333ac2a2ce2726ba1763bf2fa1956e2 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 22 Dec 2025 16:15:57 +0200 Subject: [PATCH 039/105] gh-142927: Tachyon: Comma separate thousands and fix singular/plurals (#142934) --- Lib/profiling/sampling/_format_utils.py | 5 ++ .../sampling/_heatmap_assets/heatmap.js | 4 +- Lib/profiling/sampling/cli.py | 11 +++++ Lib/profiling/sampling/heatmap_collector.py | 46 ++++++++++--------- Lib/profiling/sampling/sample.py | 44 ++++++++---------- 5 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 Lib/profiling/sampling/_format_utils.py diff --git a/Lib/profiling/sampling/_format_utils.py b/Lib/profiling/sampling/_format_utils.py new file mode 100644 index 00000000000000..237a4f4186bf20 --- /dev/null +++ b/Lib/profiling/sampling/_format_utils.py @@ -0,0 +1,5 @@ +import locale + + +def fmt(value: int | float, decimals: int = 1) -> str: + return locale.format_string(f'%.{decimals}f', value, grouping=True) diff --git a/Lib/profiling/sampling/_heatmap_assets/heatmap.js b/Lib/profiling/sampling/_heatmap_assets/heatmap.js index 90b5b111d36a8f..53928b7b20fb11 100644 --- a/Lib/profiling/sampling/_heatmap_assets/heatmap.js +++ b/Lib/profiling/sampling/_heatmap_assets/heatmap.js @@ -577,10 +577,12 @@ function populateBytecodePanel(panel, button) { else if (specPct >= 33) specClass = 'medium'; // Build specialization summary + const instruction_word = instructions.length === 1 ? 'instruction' : 'instructions'; + const sample_word = totalSamples === 1 ? 'sample' : 'samples'; let html = `
${specPct}% specialized - (${specializedCount}/${instructions.length} instructions, ${specializedSamples.toLocaleString()}/${totalSamples.toLocaleString()} samples) + (${specializedCount}/${instructions.length} ${instruction_word}, ${specializedSamples.toLocaleString()}/${totalSamples.toLocaleString()} ${sample_word})
`; html += '
' + diff --git a/Lib/profiling/sampling/cli.py b/Lib/profiling/sampling/cli.py index 554167e43f5ed8..aacec645c3479c 100644 --- a/Lib/profiling/sampling/cli.py +++ b/Lib/profiling/sampling/cli.py @@ -2,6 +2,7 @@ import argparse import importlib.util +import locale import os import selectors import socket @@ -634,6 +635,16 @@ def _validate_args(args, parser): def main(): """Main entry point for the CLI.""" + # Set locale for number formatting, restore on exit + old_locale = locale.setlocale(locale.LC_ALL, None) + locale.setlocale(locale.LC_ALL, "") + try: + _main() + finally: + locale.setlocale(locale.LC_ALL, old_locale) + + +def _main(): # Create the main parser parser = argparse.ArgumentParser( description=_HELP_DESCRIPTION, diff --git a/Lib/profiling/sampling/heatmap_collector.py b/Lib/profiling/sampling/heatmap_collector.py index e6701901aa385c..d9dabd664b3245 100644 --- a/Lib/profiling/sampling/heatmap_collector.py +++ b/Lib/profiling/sampling/heatmap_collector.py @@ -5,6 +5,7 @@ import html import importlib.resources import json +import locale import math import os import platform @@ -15,6 +16,7 @@ from typing import Dict, List, Tuple from ._css_utils import get_combined_css +from ._format_utils import fmt from .collector import normalize_location, extract_lineno from .stack_collector import StackTraceCollector @@ -343,7 +345,7 @@ def render_hierarchical_html(self, trees: Dict[str, TreeNode]) -> str:
{icon} {type_names[module_type]} - ({tree.count} {file_word}, {tree.samples:,} {sample_word}) + ({tree.count} {file_word}, {tree.samples:n} {sample_word})
''' @@ -390,7 +392,7 @@ def _render_folder(self, node: TreeNode, name: str, level: int = 1) -> str: parts.append(f'{indent} ') parts.append(f'{indent} 📁 {html.escape(name)}') parts.append(f'{indent} ' - f'({node.count} {file_word}, {node.samples:,} {sample_word})') + f'({node.count} {file_word}, {node.samples:n} {sample_word})') parts.append(f'{indent}
') parts.append(f'{indent}