From 54bedcf714160c3ecff3103a53f6291a7e1efd27 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 19 Jan 2026 03:38:37 +0900 Subject: [PATCH 001/133] gh-144012: Check null binary op extend (#144014) --- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_metadata.h | 2 +- .../2026-01-19-02-33-45.gh-issue-144012.wVEEWs.rst | 1 + Modules/_testinternalcapi/test_cases.c.h | 3 +++ Python/bytecodes.c | 1 + Python/executor_cases.c.h | 4 ++++ Python/generated_cases.c.h | 3 +++ 7 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-02-33-45.gh-issue-144012.wVEEWs.rst diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index e3f7f5a6f0b..ce6324d0a8e 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1094,7 +1094,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [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 | HAS_ERROR_NO_POP_FLAG }, - [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_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 }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 7989c2f3366..6398448d5fa 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -115,7 +115,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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, + [_BINARY_OP_EXTEND] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-02-33-45.gh-issue-144012.wVEEWs.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-02-33-45.gh-issue-144012.wVEEWs.rst new file mode 100644 index 00000000000..716a6e149cf --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-02-33-45.gh-issue-144012.wVEEWs.rst @@ -0,0 +1 @@ +Check if the result is ``NULL`` in ``BINARY_OP_EXTENT`` opcode. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index fb584314ef4..c02d236fc3e 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -359,6 +359,9 @@ stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + if (res_o == NULL) { + JUMP_TO_LABEL(error); + } res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[0] = res; diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9058a5210e5..5f2461df8e6 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -839,6 +839,7 @@ dummy_func( PyObject *res_o = d->action(left_o, right_o); DECREF_INPUTS(); + ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 6469deb238f..8f9b62b0bab 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5176,6 +5176,10 @@ stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + if (res_o == NULL) { + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } res = PyStackRef_FromPyObjectSteal(res_o); _tos_cache0 = res; _tos_cache1 = PyStackRef_ZERO_BITS; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index b5ae600c095..194fbe4f268 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -359,6 +359,9 @@ stack_pointer = _PyFrame_GetStackPointer(frame); stack_pointer += -2; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + if (res_o == NULL) { + JUMP_TO_LABEL(error); + } res = PyStackRef_FromPyObjectSteal(res_o); } stack_pointer[0] = res; From c879b2a7a52549dd310aa1cca1a00ff8f36a25ba Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> Date: Sun, 18 Jan 2026 14:04:18 -0800 Subject: [PATCH 002/133] gh-141860: Add on_error= keyword arg to `multiprocessing.set_forkserver_preload` (GH-141859) Add a keyword-only `on_error` parameter to `multiprocessing.set_forkserver_preload()`. This allows the user to have exceptions during optional `forkserver` start method module preloading cause the forkserver subprocess to warn (generally to stderr) or exit with an error (preventing use of the forkserver) instead of being silently ignored. This _also_ fixes an oversight, errors when preloading a `__main__` module are now treated the similarly. Those would always raise unlike other modules in preload, but that had gone unnoticed as up until bug fix PR GH-135295 in 3.14.1 and 3.13.8, the `__main__` module was never actually preloaded. Based on original work by Nick Neumann @aggieNick02 in GH-99515. --- Doc/library/multiprocessing.rst | 18 +- Lib/multiprocessing/context.py | 9 +- Lib/multiprocessing/forkserver.py | 110 +++++++-- .../__init__.py | 3 + .../test_preload.py | 230 ++++++++++++++++++ Misc/ACKS | 1 + ...-11-22-20-30-00.gh-issue-141860.frksvr.rst | 5 + 7 files changed, 346 insertions(+), 30 deletions(-) create mode 100644 Lib/test/test_multiprocessing_forkserver/test_preload.py create mode 100644 Misc/NEWS.d/next/Library/2025-11-22-20-30-00.gh-issue-141860.frksvr.rst diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst index 88813c6f1a4..b158ee1d42c 100644 --- a/Doc/library/multiprocessing.rst +++ b/Doc/library/multiprocessing.rst @@ -1234,22 +1234,32 @@ Miscellaneous .. versionchanged:: 3.11 Accepts a :term:`path-like object`. -.. function:: set_forkserver_preload(module_names) +.. function:: set_forkserver_preload(module_names, *, on_error='ignore') Set a list of module names for the forkserver main process to attempt to import so that their already imported state is inherited by forked - processes. Any :exc:`ImportError` when doing so is silently ignored. - This can be used as a performance enhancement to avoid repeated work - in every process. + processes. This can be used as a performance enhancement to avoid repeated + work in every process. For this to work, it must be called before the forkserver process has been launched (before creating a :class:`Pool` or starting a :class:`Process`). + The *on_error* parameter controls how :exc:`ImportError` exceptions during + module preloading are handled: ``"ignore"`` (default) silently ignores + failures, ``"warn"`` causes the forkserver subprocess to emit an + :exc:`ImportWarning` to stderr, and ``"fail"`` causes the forkserver + subprocess to exit with the exception traceback on stderr, making + subsequent process creation fail with :exc:`EOFError` or + :exc:`ConnectionError`. + Only meaningful when using the ``'forkserver'`` start method. See :ref:`multiprocessing-start-methods`. .. versionadded:: 3.4 + .. versionchanged:: next + Added the *on_error* parameter. + .. function:: set_start_method(method, force=False) Set the method which should be used to start child processes. diff --git a/Lib/multiprocessing/context.py b/Lib/multiprocessing/context.py index 051d567d457..a73261cde85 100644 --- a/Lib/multiprocessing/context.py +++ b/Lib/multiprocessing/context.py @@ -177,12 +177,15 @@ def set_executable(self, executable): from .spawn import set_executable set_executable(executable) - def set_forkserver_preload(self, module_names): + def set_forkserver_preload(self, module_names, *, on_error='ignore'): '''Set list of module names to try to load in forkserver process. - This is really just a hint. + + The on_error parameter controls how import failures are handled: + "ignore" (default) silently ignores failures, "warn" emits warnings, + and "fail" raises exceptions breaking the forkserver context. ''' from .forkserver import set_forkserver_preload - set_forkserver_preload(module_names) + set_forkserver_preload(module_names, on_error=on_error) def get_context(self, method=None): if method is None: diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py index 15c455a598d..d89b24ac59b 100644 --- a/Lib/multiprocessing/forkserver.py +++ b/Lib/multiprocessing/forkserver.py @@ -42,6 +42,7 @@ def __init__(self): self._inherited_fds = None self._lock = threading.Lock() self._preload_modules = ['__main__'] + self._preload_on_error = 'ignore' def _stop(self): # Method used by unit tests to stop the server @@ -64,11 +65,22 @@ def _stop_unlocked(self): self._forkserver_address = None self._forkserver_authkey = None - def set_forkserver_preload(self, modules_names): - '''Set list of module names to try to load in forkserver process.''' + def set_forkserver_preload(self, modules_names, *, on_error='ignore'): + '''Set list of module names to try to load in forkserver process. + + The on_error parameter controls how import failures are handled: + "ignore" (default) silently ignores failures, "warn" emits warnings, + and "fail" raises exceptions breaking the forkserver context. + ''' if not all(type(mod) is str for mod in modules_names): raise TypeError('module_names must be a list of strings') + if on_error not in ('ignore', 'warn', 'fail'): + raise ValueError( + f"on_error must be 'ignore', 'warn', or 'fail', " + f"not {on_error!r}" + ) self._preload_modules = modules_names + self._preload_on_error = on_error def get_inherited_fds(self): '''Return list of fds inherited from parent process. @@ -107,6 +119,14 @@ def connect_to_new_process(self, fds): wrapped_client, self._forkserver_authkey) connection.deliver_challenge( wrapped_client, self._forkserver_authkey) + except (EOFError, ConnectionError, BrokenPipeError) as exc: + if (self._preload_modules and + self._preload_on_error == 'fail'): + exc.add_note( + "Forkserver process may have crashed during module " + "preloading. Check stderr." + ) + raise finally: wrapped_client._detach() del wrapped_client @@ -154,6 +174,8 @@ def ensure_running(self): main_kws['main_path'] = data['init_main_from_path'] if 'sys_argv' in data: main_kws['sys_argv'] = data['sys_argv'] + if self._preload_on_error != 'ignore': + main_kws['on_error'] = self._preload_on_error with socket.socket(socket.AF_UNIX) as listener: address = connection.arbitrary_address('AF_UNIX') @@ -198,8 +220,69 @@ def ensure_running(self): # # +def _handle_import_error(on_error, modinfo, exc, *, warn_stacklevel): + """Handle an import error according to the on_error policy.""" + match on_error: + case 'fail': + raise + case 'warn': + warnings.warn( + f"Failed to preload {modinfo}: {exc}", + ImportWarning, + stacklevel=warn_stacklevel + 1 + ) + case 'ignore': + pass + + +def _handle_preload(preload, main_path=None, sys_path=None, sys_argv=None, + on_error='ignore'): + """Handle module preloading with configurable error handling. + + Args: + preload: List of module names to preload. + main_path: Path to __main__ module if '__main__' is in preload. + sys_path: sys.path to use for imports (None means use current). + sys_argv: sys.argv to use (None means use current). + on_error: How to handle import errors ("ignore", "warn", or "fail"). + """ + if not preload: + return + + if sys_argv is not None: + sys.argv[:] = sys_argv + if sys_path is not None: + sys.path[:] = sys_path + + if '__main__' in preload and main_path is not None: + process.current_process()._inheriting = True + try: + spawn.import_main_path(main_path) + except Exception as e: + # Catch broad Exception because import_main_path() uses + # runpy.run_path() which executes the script and can raise + # any exception, not just ImportError + _handle_import_error( + on_error, f"__main__ from {main_path!r}", e, warn_stacklevel=2 + ) + finally: + del process.current_process()._inheriting + + for modname in preload: + try: + __import__(modname) + except ImportError as e: + _handle_import_error( + on_error, f"module {modname!r}", e, warn_stacklevel=2 + ) + + # gh-135335: flush stdout/stderr in case any of the preloaded modules + # wrote to them, otherwise children might inherit buffered data + util._flush_std_streams() + + def main(listener_fd, alive_r, preload, main_path=None, sys_path=None, - *, sys_argv=None, authkey_r=None): + *, sys_argv=None, authkey_r=None, on_error='ignore'): """Run forkserver.""" if authkey_r is not None: try: @@ -210,26 +293,7 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None, else: authkey = b'' - if preload: - if sys_argv is not None: - sys.argv[:] = sys_argv - if sys_path is not None: - sys.path[:] = sys_path - if '__main__' in preload and main_path is not None: - process.current_process()._inheriting = True - try: - spawn.import_main_path(main_path) - finally: - del process.current_process()._inheriting - for modname in preload: - try: - __import__(modname) - except ImportError: - pass - - # gh-135335: flush stdout/stderr in case any of the preloaded modules - # wrote to them, otherwise children might inherit buffered data - util._flush_std_streams() + _handle_preload(preload, main_path, sys_path, sys_argv, on_error) util._close_stdin() diff --git a/Lib/test/test_multiprocessing_forkserver/__init__.py b/Lib/test/test_multiprocessing_forkserver/__init__.py index d91715a344d..7b1b884ab29 100644 --- a/Lib/test/test_multiprocessing_forkserver/__init__.py +++ b/Lib/test/test_multiprocessing_forkserver/__init__.py @@ -9,5 +9,8 @@ if sys.platform == "win32": raise unittest.SkipTest("forkserver is not available on Windows") +if not support.has_fork_support: + raise unittest.SkipTest("requires working os.fork()") + def load_tests(*args): return support.load_package_tests(os.path.dirname(__file__), *args) diff --git a/Lib/test/test_multiprocessing_forkserver/test_preload.py b/Lib/test/test_multiprocessing_forkserver/test_preload.py new file mode 100644 index 00000000000..f8e119aa367 --- /dev/null +++ b/Lib/test/test_multiprocessing_forkserver/test_preload.py @@ -0,0 +1,230 @@ +"""Tests for forkserver preload functionality.""" + +import contextlib +import multiprocessing +import os +import shutil +import sys +import tempfile +import unittest +from multiprocessing import forkserver, spawn + + +class TestForkserverPreload(unittest.TestCase): + """Tests for forkserver preload functionality.""" + + def setUp(self): + self._saved_warnoptions = sys.warnoptions.copy() + # Remove warning options that would convert ImportWarning to errors: + # - 'error' converts all warnings to errors + # - 'error::ImportWarning' specifically converts ImportWarning + # Keep other specific options like 'error::BytesWarning' that + # subprocess's _args_from_interpreter_flags() expects to remove + sys.warnoptions[:] = [ + opt for opt in sys.warnoptions + if opt not in ('error', 'error::ImportWarning') + ] + self.ctx = multiprocessing.get_context('forkserver') + forkserver._forkserver._stop() + + def tearDown(self): + sys.warnoptions[:] = self._saved_warnoptions + forkserver._forkserver._stop() + + @staticmethod + def _send_value(conn, value): + """Send value through connection. Static method to be picklable as Process target.""" + conn.send(value) + + @contextlib.contextmanager + def capture_forkserver_stderr(self): + """Capture stderr from forkserver by preloading a module that redirects it. + + Yields (module_name, capture_file_path). The capture file can be read + after the forkserver has processed preloads. This works because + forkserver.main() calls util._flush_std_streams() after preloading, + ensuring captured output is written before we read it. + """ + tmpdir = tempfile.mkdtemp() + capture_module = os.path.join(tmpdir, '_capture_stderr.py') + capture_file = os.path.join(tmpdir, 'stderr.txt') + try: + with open(capture_module, 'w') as f: + # Use line buffering (buffering=1) to ensure warnings are written. + # Enable ImportWarning since it's ignored by default. + f.write( + f'import sys, warnings; ' + f'sys.stderr = open({capture_file!r}, "w", buffering=1); ' + f'warnings.filterwarnings("always", category=ImportWarning)\n' + ) + sys.path.insert(0, tmpdir) + yield '_capture_stderr', capture_file + finally: + sys.path.remove(tmpdir) + shutil.rmtree(tmpdir, ignore_errors=True) + + def test_preload_on_error_ignore_default(self): + """Test that invalid modules are silently ignored by default.""" + self.ctx.set_forkserver_preload(['nonexistent_module_xyz']) + + r, w = self.ctx.Pipe(duplex=False) + p = self.ctx.Process(target=self._send_value, args=(w, 42)) + p.start() + w.close() + result = r.recv() + r.close() + p.join() + + self.assertEqual(result, 42) + self.assertEqual(p.exitcode, 0) + + def test_preload_on_error_ignore_explicit(self): + """Test that invalid modules are silently ignored with on_error='ignore'.""" + self.ctx.set_forkserver_preload(['nonexistent_module_xyz'], on_error='ignore') + + r, w = self.ctx.Pipe(duplex=False) + p = self.ctx.Process(target=self._send_value, args=(w, 99)) + p.start() + w.close() + result = r.recv() + r.close() + p.join() + + self.assertEqual(result, 99) + self.assertEqual(p.exitcode, 0) + + def test_preload_on_error_warn(self): + """Test that invalid modules emit warnings with on_error='warn'.""" + with self.capture_forkserver_stderr() as (capture_mod, stderr_file): + self.ctx.set_forkserver_preload( + [capture_mod, 'nonexistent_module_xyz'], on_error='warn') + + r, w = self.ctx.Pipe(duplex=False) + p = self.ctx.Process(target=self._send_value, args=(w, 123)) + p.start() + w.close() + result = r.recv() + r.close() + p.join() + + self.assertEqual(result, 123) + self.assertEqual(p.exitcode, 0) + + with open(stderr_file) as f: + stderr_output = f.read() + self.assertIn('nonexistent_module_xyz', stderr_output) + self.assertIn('ImportWarning', stderr_output) + + def test_preload_on_error_fail_breaks_context(self): + """Test that invalid modules with on_error='fail' breaks the forkserver.""" + with self.capture_forkserver_stderr() as (capture_mod, stderr_file): + self.ctx.set_forkserver_preload( + [capture_mod, 'nonexistent_module_xyz'], on_error='fail') + + r, w = self.ctx.Pipe(duplex=False) + try: + p = self.ctx.Process(target=self._send_value, args=(w, 42)) + with self.assertRaises((EOFError, ConnectionError, BrokenPipeError)) as cm: + p.start() + notes = getattr(cm.exception, '__notes__', []) + self.assertTrue(notes, "Expected exception to have __notes__") + self.assertIn('Forkserver process may have crashed', notes[0]) + + with open(stderr_file) as f: + stderr_output = f.read() + self.assertIn('nonexistent_module_xyz', stderr_output) + self.assertIn('ModuleNotFoundError', stderr_output) + finally: + w.close() + r.close() + + def test_preload_valid_modules_with_on_error_fail(self): + """Test that valid modules work fine with on_error='fail'.""" + self.ctx.set_forkserver_preload(['os', 'sys'], on_error='fail') + + r, w = self.ctx.Pipe(duplex=False) + p = self.ctx.Process(target=self._send_value, args=(w, 'success')) + p.start() + w.close() + result = r.recv() + r.close() + p.join() + + self.assertEqual(result, 'success') + self.assertEqual(p.exitcode, 0) + + def test_preload_invalid_on_error_value(self): + """Test that invalid on_error values raise ValueError.""" + with self.assertRaises(ValueError) as cm: + self.ctx.set_forkserver_preload(['os'], on_error='invalid') + self.assertIn("on_error must be 'ignore', 'warn', or 'fail'", str(cm.exception)) + + +class TestHandlePreload(unittest.TestCase): + """Unit tests for _handle_preload() function.""" + + def setUp(self): + self._saved_main = sys.modules['__main__'] + + def tearDown(self): + spawn.old_main_modules.clear() + sys.modules['__main__'] = self._saved_main + + def test_handle_preload_main_on_error_fail(self): + """Test that __main__ import failures raise with on_error='fail'.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f: + f.write('raise RuntimeError("test error in __main__")\n') + f.flush() + with self.assertRaises(RuntimeError) as cm: + forkserver._handle_preload(['__main__'], main_path=f.name, on_error='fail') + self.assertIn("test error in __main__", str(cm.exception)) + + def test_handle_preload_main_on_error_warn(self): + """Test that __main__ import failures warn with on_error='warn'.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f: + f.write('raise ImportError("test import error")\n') + f.flush() + with self.assertWarns(ImportWarning) as cm: + forkserver._handle_preload(['__main__'], main_path=f.name, on_error='warn') + self.assertIn("Failed to preload __main__", str(cm.warning)) + self.assertIn("test import error", str(cm.warning)) + + def test_handle_preload_main_on_error_ignore(self): + """Test that __main__ import failures are ignored with on_error='ignore'.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f: + f.write('raise ImportError("test import error")\n') + f.flush() + forkserver._handle_preload(['__main__'], main_path=f.name, on_error='ignore') + + def test_handle_preload_main_valid(self): + """Test that valid __main__ preload works.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f: + f.write('test_var = 42\n') + f.flush() + forkserver._handle_preload(['__main__'], main_path=f.name, on_error='fail') + + def test_handle_preload_module_on_error_fail(self): + """Test that module import failures raise with on_error='fail'.""" + with self.assertRaises(ModuleNotFoundError): + forkserver._handle_preload(['nonexistent_test_module_xyz'], on_error='fail') + + def test_handle_preload_module_on_error_warn(self): + """Test that module import failures warn with on_error='warn'.""" + with self.assertWarns(ImportWarning) as cm: + forkserver._handle_preload(['nonexistent_test_module_xyz'], on_error='warn') + self.assertIn("Failed to preload module", str(cm.warning)) + + def test_handle_preload_module_on_error_ignore(self): + """Test that module import failures are ignored with on_error='ignore'.""" + forkserver._handle_preload(['nonexistent_test_module_xyz'], on_error='ignore') + + def test_handle_preload_combined(self): + """Test preloading both __main__ and modules.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as f: + f.write('import sys\n') + f.flush() + forkserver._handle_preload(['__main__', 'os', 'sys'], main_path=f.name, on_error='fail') + + +if __name__ == '__main__': + unittest.main() diff --git a/Misc/ACKS b/Misc/ACKS index 49a8deb30fc..feb16a62792 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1340,6 +1340,7 @@ Trent Nelson Andrew Nester Osvaldo Santana Neto Chad Netzer +Nick Neumann Max Neunhöffer Anthon van der Neut George Neville-Neil diff --git a/Misc/NEWS.d/next/Library/2025-11-22-20-30-00.gh-issue-141860.frksvr.rst b/Misc/NEWS.d/next/Library/2025-11-22-20-30-00.gh-issue-141860.frksvr.rst new file mode 100644 index 00000000000..b1efd9c014f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-22-20-30-00.gh-issue-141860.frksvr.rst @@ -0,0 +1,5 @@ +Add an ``on_error`` keyword-only parameter to +:func:`multiprocessing.set_forkserver_preload` to control how import failures +during module preloading are handled. Accepts ``'ignore'`` (default, silent), +``'warn'`` (emit :exc:`ImportWarning`), or ``'fail'`` (raise exception). +Contributed by Nick Neumann and Gregory P. Smith. From 78b1370de96bab5eee82b022a9e26e633a040e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=BA=F0=9F=87=A6=20Sviatoslav=20Sydorenko=20=28?= =?UTF-8?q?=D0=A1=D0=B2=D1=8F=D1=82=D0=BE=D1=81=D0=BB=D0=B0=D0=B2=20=D0=A1?= =?UTF-8?q?=D0=B8=D0=B4=D0=BE=D1=80=D0=B5=D0=BD=D0=BA=D0=BE=29?= Date: Sun, 18 Jan 2026 23:28:38 +0100 Subject: [PATCH 003/133] Notify Sviat of GHA changes through codeowners (#143945) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- .github/CODEOWNERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bf10e34fde1..440d4c005c6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -63,8 +63,8 @@ .azure-pipelines/ @AA-Turner # GitHub & related scripts -.github/ @ezio-melotti @hugovk @AA-Turner -Tools/build/compute-changes.py @AA-Turner +.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz +Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz Tools/build/verify_ensurepip_wheels.py @AA-Turner @pfmoore @pradyunsg # Pre-commit From 59d3594ca12939dea0a537d9964d8d637546855c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Mon, 19 Jan 2026 06:29:11 +0100 Subject: [PATCH 004/133] gh-143831: Compare cells by identity in forward references (#143848) --- Lib/annotationlib.py | 13 +++++-- Lib/test/test_annotationlib.py | 34 +++++++++++++++++++ ...-01-16-06-22-10.gh-issue-143831.VLBTLp.rst | 3 ++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-06-22-10.gh-issue-143831.VLBTLp.rst diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index 4085cc6bef7..832d160de7f 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -279,7 +279,13 @@ def __eq__(self, other): # because dictionaries are not hashable. and self.__globals__ is other.__globals__ and self.__forward_is_class__ == other.__forward_is_class__ - and self.__cell__ == other.__cell__ + # Two separate cells are always considered unequal in forward refs. + and ( + {name: id(cell) for name, cell in self.__cell__.items()} + == {name: id(cell) for name, cell in other.__cell__.items()} + if isinstance(self.__cell__, dict) and isinstance(other.__cell__, dict) + else self.__cell__ is other.__cell__ + ) and self.__owner__ == other.__owner__ and ( (tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None) == @@ -293,7 +299,10 @@ def __hash__(self): self.__forward_module__, id(self.__globals__), # dictionaries are not hashable, so hash by identity self.__forward_is_class__, - tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__, + ( # cells are not hashable as well + tuple(sorted([(name, id(cell)) for name, cell in self.__cell__.items()])) + if isinstance(self.__cell__, dict) else id(self.__cell__), + ), self.__owner__, tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None, )) diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index a8537871d29..6b75da32fa9 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -8,6 +8,7 @@ import itertools import pickle from string.templatelib import Template, Interpolation +import types import typing import sys import unittest @@ -1862,6 +1863,39 @@ def foo(a: c1_gth, b: c2_gth): self.assertNotEqual(hash(c3), hash(c4)) self.assertEqual(hash(c3), hash(ForwardRef("int", module=__name__))) + def test_forward_equality_and_hash_with_cells(self): + """Regression test for GH-143831.""" + class A: + def one(_) -> C1: + """One cell.""" + + one_f = ForwardRef("C1", owner=one) + one_f_ga1 = get_annotations(one, format=Format.FORWARDREF)["return"] + one_f_ga2 = get_annotations(one, format=Format.FORWARDREF)["return"] + self.assertIsInstance(one_f_ga1.__cell__, types.CellType) + self.assertIs(one_f_ga1.__cell__, one_f_ga2.__cell__) + + def two(_) -> C1 | C2: + """Two cells.""" + + two_f_ga1 = get_annotations(two, format=Format.FORWARDREF)["return"] + two_f_ga2 = get_annotations(two, format=Format.FORWARDREF)["return"] + self.assertIsNot(two_f_ga1.__cell__, two_f_ga2.__cell__) + self.assertIsInstance(two_f_ga1.__cell__, dict) + self.assertIsInstance(two_f_ga2.__cell__, dict) + + type C1 = None + type C2 = None + + self.assertNotEqual(A.one_f, A.one_f_ga1) + self.assertNotEqual(hash(A.one_f), hash(A.one_f_ga1)) + + self.assertEqual(A.one_f_ga1, A.one_f_ga2) + self.assertEqual(hash(A.one_f_ga1), hash(A.one_f_ga2)) + + self.assertEqual(A.two_f_ga1, A.two_f_ga2) + self.assertEqual(hash(A.two_f_ga1), hash(A.two_f_ga2)) + def test_forward_equality_namespace(self): def namespace1(): a = ForwardRef("A") diff --git a/Misc/NEWS.d/next/Library/2026-01-16-06-22-10.gh-issue-143831.VLBTLp.rst b/Misc/NEWS.d/next/Library/2026-01-16-06-22-10.gh-issue-143831.VLBTLp.rst new file mode 100644 index 00000000000..620adea1b6d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-06-22-10.gh-issue-143831.VLBTLp.rst @@ -0,0 +1,3 @@ +:class:`annotationlib.ForwardRef` objects are now hashable when created from +annotation scopes with closures. Previously, hashing such objects would +throw an exception. Patch by Bartosz Sławecki. From d8ab1c79b0e3f1406263c084c7d09a78cc128187 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 19 Jan 2026 13:22:16 +0300 Subject: [PATCH 005/133] gh-75459: versionadded for PyObject_CallFinalizer*() API (GH-143982) --- Doc/c-api/lifecycle.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Doc/c-api/lifecycle.rst b/Doc/c-api/lifecycle.rst index 5a170862a26..531c4080a01 100644 --- a/Doc/c-api/lifecycle.rst +++ b/Doc/c-api/lifecycle.rst @@ -256,6 +256,8 @@ To allocate and free memory, see :ref:`allocating-objects`. collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set); this may change in the future. + .. versionadded:: 3.4 + .. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op) @@ -266,6 +268,8 @@ To allocate and free memory, see :ref:`allocating-objects`. should happen. Otherwise, this function returns 0 and destruction can continue normally. + .. versionadded:: 3.4 + .. seealso:: :c:member:`~PyTypeObject.tp_dealloc` for example code. From cb6a662bb0f7a9da9d4ba9dda820053f8d54a9f8 Mon Sep 17 00:00:00 2001 From: b9788213 Date: Mon, 19 Jan 2026 14:24:20 +0300 Subject: [PATCH 006/133] gh-143866: Verify return value of `pathlib.write_{bytes,text}` methods in tests (#143870) Co-authored-by: sobolevn --- Lib/test/test_pathlib/test_write.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_pathlib/test_write.py b/Lib/test/test_pathlib/test_write.py index c9c1d64656c..fa2a81a47b3 100644 --- a/Lib/test/test_pathlib/test_write.py +++ b/Lib/test/test_pathlib/test_write.py @@ -65,15 +65,17 @@ def test_open_wb(self): def test_write_bytes(self): p = self.root / 'fileA' - p.write_bytes(b'abcdefg') - self.assertEqual(self.ground.readbytes(p), b'abcdefg') + data = b'abcdefg' + self.assertEqual(len(data), p.write_bytes(data)) + self.assertEqual(self.ground.readbytes(p), data) # Check that trying to write str does not truncate the file. self.assertRaises(TypeError, p.write_bytes, 'somestr') - self.assertEqual(self.ground.readbytes(p), b'abcdefg') + self.assertEqual(self.ground.readbytes(p), data) def test_write_text(self): p = self.root / 'fileA' - p.write_text('äbcdefg', encoding='latin-1') + data = 'äbcdefg' + self.assertEqual(len(data), p.write_text(data, encoding='latin-1')) self.assertEqual(self.ground.readbytes(p), b'\xe4bcdefg') # Check that trying to write bytes does not truncate the file. self.assertRaises(TypeError, p.write_text, b'somebytes', encoding='utf-8') From 813fc7a291c98654c27f2b5d8f9afa8e53b066a6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 19 Jan 2026 14:01:29 +0200 Subject: [PATCH 007/133] gh-143754: Modernize Tkinter docs (GH-143841) Use more relevant terminology instead of "master"/"slave" widgets where possible. --- Doc/library/tkinter.rst | 26 +++++++------- Lib/tkinter/__init__.py | 79 +++++++++++++++++++++++------------------ 2 files changed, 58 insertions(+), 47 deletions(-) diff --git a/Doc/library/tkinter.rst b/Doc/library/tkinter.rst index 81177533be8..07ce8c40577 100644 --- a/Doc/library/tkinter.rst +++ b/Doc/library/tkinter.rst @@ -177,12 +177,12 @@ the modern themed widget set and API:: .. attribute:: master The widget object that contains this widget. For :class:`Tk`, the - *master* is :const:`None` because it is the main window. The terms + :attr:`!master` is :const:`None` because it is the main window. The terms *master* and *parent* are similar and sometimes used interchangeably as argument names; however, calling :meth:`winfo_parent` returns a - string of the widget name whereas :attr:`master` returns the object. + string of the widget name whereas :attr:`!master` returns the object. *parent*/*child* reflects the tree-like relationship while - *master*/*slave* reflects the container structure. + *master* (or *container*)/*content* reflects the container structure. .. attribute:: children @@ -638,15 +638,15 @@ The Packer .. index:: single: packing (widgets) The packer is one of Tk's geometry-management mechanisms. Geometry managers -are used to specify the relative positioning of widgets within their container - -their mutual *master*. In contrast to the more cumbersome *placer* (which is +are used to specify the relative positioning of widgets within their container. +In contrast to the more cumbersome *placer* (which is used less commonly, and we do not cover here), the packer takes qualitative relationship specification - *above*, *to the left of*, *filling*, etc - and works everything out to determine the exact placement coordinates for you. -The size of any *master* widget is determined by the size of the "slave widgets" -inside. The packer is used to control where slave widgets appear inside the -master into which they are packed. You can pack widgets into frames, and frames +The size of any container widget is determined by the size of the "content widgets" +inside. The packer is used to control where content widgets appear inside the +container into which they are packed. You can pack widgets into frames, and frames into other frames, in order to achieve the kind of layout you desire. Additionally, the arrangement is dynamically adjusted to accommodate incremental changes to the configuration, once it is packed. @@ -673,7 +673,7 @@ For more extensive information on the packer and the options that it can take, see the man pages and page 183 of John Ousterhout's book. anchor - Anchor type. Denotes where the packer is to place each slave in its parcel. + Anchor type. Denotes where the packer is to place each content in its parcel. expand Boolean, ``0`` or ``1``. @@ -682,10 +682,10 @@ fill Legal values: ``'x'``, ``'y'``, ``'both'``, ``'none'``. ipadx and ipady - A distance - designating internal padding on each side of the slave widget. + A distance - designating internal padding on each side of the content. padx and pady - A distance - designating external padding on each side of the slave widget. + A distance - designating external padding on each side of the content. side Legal values are: ``'left'``, ``'right'``, ``'top'``, ``'bottom'``. @@ -758,8 +758,8 @@ subclassed from the :class:`Wm` class, and so can call the :class:`Wm` methods directly. To get at the toplevel window that contains a given widget, you can often just -refer to the widget's master. Of course if the widget has been packed inside of -a frame, the master won't represent a toplevel window. To get at the toplevel +refer to the widget's :attr:`master`. Of course if the widget has been packed inside of +a frame, the :attr:`!master` won't represent a toplevel window. To get at the toplevel window that contains an arbitrary widget, you can call the :meth:`_root` method. This method begins with an underscore to denote the fact that this function is part of the implementation, and not an interface to Tk functionality. diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index 737583a42c6..be150e2b892 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1867,15 +1867,15 @@ def __repr__(self): return '<%s.%s object %s>' % ( self.__class__.__module__, self.__class__.__qualname__, self._w) - # Pack methods that apply to the master + # Pack methods that apply to the container widget _noarg_ = ['_noarg_'] def pack_propagate(self, flag=_noarg_): """Set or get the status for propagation of geometry information. - A boolean argument specifies whether the geometry information - of the slaves will determine the size of this widget. If no argument - is given the current setting will be returned. + A boolean argument specifies whether the size of this container will + be determined by the geometry information of its content. + If no argument is given the current setting will be returned. """ if flag is Misc._noarg_: return self._getboolean(self.tk.call( @@ -1886,28 +1886,28 @@ def pack_propagate(self, flag=_noarg_): propagate = pack_propagate def pack_slaves(self): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of all of the content widgets in the packing order + for this container.""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call('pack', 'slaves', self._w))] slaves = pack_slaves - # Place method that applies to the master + # Place method that applies to the container widget def place_slaves(self): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of all the content widgets for which this widget is + the container.""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call( 'place', 'slaves', self._w))] - # Grid methods that apply to the master + # Grid methods that apply to the container widget def grid_anchor(self, anchor=None): # new in Tk 8.5 """The anchor value controls how to place the grid within the - master when no row/column has any weight. + container widget when no row/column has any weight. The default anchor is nw.""" self.tk.call('grid', 'anchor', self._w, anchor) @@ -1924,7 +1924,7 @@ def grid_bbox(self, column=None, row=None, col2=None, row2=None): starts at that cell. The returned integers specify the offset of the upper left - corner in the master widget and the width and height. + corner in the container widget and the width and height. """ args = ('grid', 'bbox', self._w) if column is not None and row is not None: @@ -1982,7 +1982,7 @@ def grid_columnconfigure(self, index, cnf={}, **kw): def grid_location(self, x, y): """Return a tuple of column and row which identify the cell - at which the pixel at position X and Y inside the master + at which the pixel at position X and Y inside the container widget is located.""" return self._getints( self.tk.call( @@ -1991,9 +1991,9 @@ def grid_location(self, x, y): def grid_propagate(self, flag=_noarg_): """Set or get the status for propagation of geometry information. - A boolean argument specifies whether the geometry information - of the slaves will determine the size of this widget. If no argument - is given, the current setting will be returned. + A boolean argument specifies whether the size of this container will + be determined by the geometry information of its content. + If no argument is given the current setting will be returned. """ if flag is Misc._noarg_: return self._getboolean(self.tk.call( @@ -2019,8 +2019,13 @@ def grid_size(self): size = grid_size def grid_slaves(self, row=None, column=None): - """Return a list of all slaves of this widget - in its packing order.""" + """Returns a list of the content widgets. + + If no arguments are supplied, a list of all of the content in this + container widget is returned, most recently managed first. + If ROW or COLUMN is specified, only the content in the row or + column is returned. + """ args = () if row is not None: args = args + ('-row', row) @@ -2606,8 +2611,8 @@ def pack_configure(self, cnf={}, **kw): before=widget - pack it before you will pack widget expand=bool - expand widget if parent size grows fill=NONE or X or Y or BOTH - fill widget if widget grows - in=master - use master to contain this widget - in_=master - see 'in' option description + in=container - use the container widget to contain this widget + in_=container - see 'in' option description ipadx=amount - add internal padding in x direction ipady=amount - add internal padding in y direction padx=amount - add padding in x direction @@ -2646,25 +2651,31 @@ class Place: def place_configure(self, cnf={}, **kw): """Place a widget in the parent widget. Use as options: - in=master - master relative to which the widget is placed - in_=master - see 'in' option description - x=amount - locate anchor of this widget at position x of master - y=amount - locate anchor of this widget at position y of master + in=container - the container widget relative to which this widget is + placed + in_=container - see 'in' option description + x=amount - locate anchor of this widget at position x of the + container widget + y=amount - locate anchor of this widget at position y of the + container widget relx=amount - locate anchor of this widget between 0.0 and 1.0 - relative to width of master (1.0 is right edge) + relative to width of the container widget (1.0 is + right edge) rely=amount - locate anchor of this widget between 0.0 and 1.0 - relative to height of master (1.0 is bottom edge) - anchor=NSEW (or subset) - position anchor according to given direction + relative to height of the container widget (1.0 is + bottom edge) + anchor=NSEW (or subset) - position anchor according to given + direction width=amount - width of this widget in pixel height=amount - height of this widget in pixel relwidth=amount - width of this widget between 0.0 and 1.0 - relative to width of master (1.0 is the same width - as the master) + relative to width of the container widget (1.0 is + the same width as the container widget) relheight=amount - height of this widget between 0.0 and 1.0 - relative to height of master (1.0 is the same - height as the master) + relative to height of the container widget (1.0 + is the same height as the container widget) bordermode="inside" or "outside" - whether to take border width of - master widget into account + the container widget into account """ self.tk.call( ('place', 'configure', self._w) @@ -2700,8 +2711,8 @@ def grid_configure(self, cnf={}, **kw): """Position a widget in the parent widget in a grid. Use as options: column=number - use cell identified with given column (starting with 0) columnspan=number - this widget will span several columns - in=master - use master to contain this widget - in_=master - see 'in' option description + in=container - use the container widget to contain this widget + in_=container - see 'in' option description ipadx=amount - add internal padding in x direction ipady=amount - add internal padding in y direction padx=amount - add padding in x direction From 7dca4e3af118328d7013b58106d129b162047cb3 Mon Sep 17 00:00:00 2001 From: AZero13 Date: Mon, 19 Jan 2026 07:19:20 -0500 Subject: [PATCH 008/133] gh-142440: Fix _decimal builds configured with EXTRA_FUNCTIONALITY (GH-142441) There was a typo in _decimal.Context.apply(). --- .../next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst | 2 ++ Modules/_decimal/_decimal.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst b/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst new file mode 100644 index 00000000000..5c1db433e1b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-08-18-40-17.gh-issue-142438.tH-Y16.rst @@ -0,0 +1,2 @@ +Fix _decimal builds configured with EXTRA_FUNCTIONALITY by correcting the +Context.apply wrapper to pass the right argument. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 33e624e342e..dcea4da8f24 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -6991,7 +6991,7 @@ _decimal_Context_apply_impl(PyObject *context, PyTypeObject *cls, PyObject *x) /*[clinic end generated code: output=f8a7142d47ad4ff3 input=388e66ca82733516]*/ { - return _decimal_Context__apply(context, v); + return _decimal_Context__apply(context, x); } #endif From bb2b9ba49d8a60629f0905bc27191fc84db39879 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 19 Jan 2026 14:37:41 +0200 Subject: [PATCH 009/133] gh-143897: Remove the isxidstart() and isxidcontinue() methods of unicodedata.ucd_3_2_0 (GH-143898) They are now only exposed as the unicodedata function. --- Lib/test/test_unicodedata.py | 27 +++++++------- ...-01-16-10-53-17.gh-issue-143897.hWJBHN.rst | 3 ++ Modules/clinic/unicodedata.c.h | 30 ++++++++-------- Modules/unicodedata.c | 36 +++++-------------- 4 files changed, 39 insertions(+), 57 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 07aa992de6d..f9c0cd20438 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -83,15 +83,7 @@ def test_method_checksum(self): self.assertEqual(result, self.expectedchecksum) -class UnicodeFunctionsTest(unittest.TestCase): - db = unicodedata - old = False - - # Update this if the database changes. Make sure to do a full rebuild - # (e.g. 'make distclean && make') to get the correct checksum. - expectedchecksum = ('83cc43a2fbb779185832b4c049217d80b05bf349' - if quicktest else - '65670ae03a324c5f9e826a4de3e25bae4d73c9b7') +class BaseUnicodeFunctionsTest: def test_function_checksum(self): db = self.db @@ -589,6 +581,16 @@ def test_east_asian_width_unassigned(self): self.assertEqual(eaw(char), 'A') self.assertIs(self.db.name(char, None), None) +class UnicodeFunctionsTest(unittest.TestCase, BaseUnicodeFunctionsTest): + db = unicodedata + old = False + + # Update this if the database changes. Make sure to do a full rebuild + # (e.g. 'make distclean && make') to get the correct checksum. + expectedchecksum = ('83cc43a2fbb779185832b4c049217d80b05bf349' + if quicktest else + '65670ae03a324c5f9e826a4de3e25bae4d73c9b7') + def test_isxidstart(self): self.assertTrue(self.db.isxidstart('S')) self.assertTrue(self.db.isxidstart('\u0AD0')) # GUJARATI OM @@ -832,18 +834,13 @@ def graphemes(*args): ['a', '\U0001F1FA\U0001F1E6', '\U0001F1FA\U0001F1F3']) -class Unicode_3_2_0_FunctionsTest(UnicodeFunctionsTest): +class Unicode_3_2_0_FunctionsTest(unittest.TestCase, BaseUnicodeFunctionsTest): db = unicodedata.ucd_3_2_0 old = True expectedchecksum = ('f4526159891a4b766dd48045646547178737ba09' if quicktest else 'f217b8688d7bdff31db4207e078a96702f091597') - test_grapheme_cluster_break = None - test_indic_conjunct_break = None - test_extended_pictographic = None - test_grapheme_break = None - class UnicodeMiscTest(unittest.TestCase): db = unicodedata diff --git a/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst b/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst new file mode 100644 index 00000000000..d53eac0bd35 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-10-53-17.gh-issue-143897.hWJBHN.rst @@ -0,0 +1,3 @@ +Remove the :meth:`!isxidstart` and :meth:`!isxidcontinue` methods of +:data:`unicodedata.ucd_3_2_0`. They are now only exposed as +:func:`unicodedata.isxidstart` and :func:`unicodedata.isxidcontinue`. diff --git a/Modules/clinic/unicodedata.c.h b/Modules/clinic/unicodedata.c.h index c0497cf45f6..8e2dd7a0ce5 100644 --- a/Modules/clinic/unicodedata.c.h +++ b/Modules/clinic/unicodedata.c.h @@ -519,20 +519,20 @@ exit: return return_value; } -PyDoc_STRVAR(unicodedata_UCD_isxidstart__doc__, -"isxidstart($self, chr, /)\n" +PyDoc_STRVAR(unicodedata_isxidstart__doc__, +"isxidstart($module, chr, /)\n" "--\n" "\n" "Return True if the character has the XID_Start property, else False."); -#define UNICODEDATA_UCD_ISXIDSTART_METHODDEF \ - {"isxidstart", (PyCFunction)unicodedata_UCD_isxidstart, METH_O, unicodedata_UCD_isxidstart__doc__}, +#define UNICODEDATA_ISXIDSTART_METHODDEF \ + {"isxidstart", (PyCFunction)unicodedata_isxidstart, METH_O, unicodedata_isxidstart__doc__}, static PyObject * -unicodedata_UCD_isxidstart_impl(PyObject *self, int chr); +unicodedata_isxidstart_impl(PyObject *module, int chr); static PyObject * -unicodedata_UCD_isxidstart(PyObject *self, PyObject *arg) +unicodedata_isxidstart(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int chr; @@ -549,26 +549,26 @@ unicodedata_UCD_isxidstart(PyObject *self, PyObject *arg) goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); - return_value = unicodedata_UCD_isxidstart_impl(self, chr); + return_value = unicodedata_isxidstart_impl(module, chr); exit: return return_value; } -PyDoc_STRVAR(unicodedata_UCD_isxidcontinue__doc__, -"isxidcontinue($self, chr, /)\n" +PyDoc_STRVAR(unicodedata_isxidcontinue__doc__, +"isxidcontinue($module, chr, /)\n" "--\n" "\n" "Return True if the character has the XID_Continue property, else False."); -#define UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF \ - {"isxidcontinue", (PyCFunction)unicodedata_UCD_isxidcontinue, METH_O, unicodedata_UCD_isxidcontinue__doc__}, +#define UNICODEDATA_ISXIDCONTINUE_METHODDEF \ + {"isxidcontinue", (PyCFunction)unicodedata_isxidcontinue, METH_O, unicodedata_isxidcontinue__doc__}, static PyObject * -unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr); +unicodedata_isxidcontinue_impl(PyObject *module, int chr); static PyObject * -unicodedata_UCD_isxidcontinue(PyObject *self, PyObject *arg) +unicodedata_isxidcontinue(PyObject *module, PyObject *arg) { PyObject *return_value = NULL; int chr; @@ -585,7 +585,7 @@ unicodedata_UCD_isxidcontinue(PyObject *self, PyObject *arg) goto exit; } chr = PyUnicode_READ_CHAR(arg, 0); - return_value = unicodedata_UCD_isxidcontinue_impl(self, chr); + return_value = unicodedata_isxidcontinue_impl(module, chr); exit: return return_value; @@ -798,4 +798,4 @@ unicodedata_extended_pictographic(PyObject *module, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=6991246310e3f2aa input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0f09cc90f06ace76 input=a9049054013a1b77]*/ diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index 6904ee14811..586ce8d36dd 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1565,9 +1565,8 @@ unicodedata_UCD_name_impl(PyObject *self, int chr, PyObject *default_value) } /*[clinic input] -unicodedata.UCD.isxidstart +unicodedata.isxidstart - self: self chr: int(accept={str}) / @@ -1576,24 +1575,15 @@ Return True if the character has the XID_Start property, else False. [clinic start generated code]*/ static PyObject * -unicodedata_UCD_isxidstart_impl(PyObject *self, int chr) -/*[clinic end generated code: output=944005823c72c3ef input=9353f88d709c21fb]*/ +unicodedata_isxidstart_impl(PyObject *module, int chr) +/*[clinic end generated code: output=7ae0e1a3915aa031 input=3812717f3a6bfc56]*/ { - if (UCD_Check(self)) { - const change_record *old = get_old_record(self, chr); - if (old->category_changed == 0) { - /* unassigned */ - Py_RETURN_FALSE; - } - } - return PyBool_FromLong(_PyUnicode_IsXidStart(chr)); } /*[clinic input] -unicodedata.UCD.isxidcontinue +unicodedata.isxidcontinue - self: self chr: int(accept={str}) / @@ -1602,17 +1592,9 @@ Return True if the character has the XID_Continue property, else False. [clinic start generated code]*/ static PyObject * -unicodedata_UCD_isxidcontinue_impl(PyObject *self, int chr) -/*[clinic end generated code: output=9438dcbff5ca3e41 input=bbb8dd3ac0d2d709]*/ +unicodedata_isxidcontinue_impl(PyObject *module, int chr) +/*[clinic end generated code: output=517caa8b38c73aed input=a971ed6e57cac374]*/ { - if (UCD_Check(self)) { - const change_record *old = get_old_record(self, chr); - if (old->category_changed == 0) { - /* unassigned */ - Py_RETURN_FALSE; - } - } - return PyBool_FromLong(_PyUnicode_IsXidContinue(chr)); } @@ -2128,10 +2110,12 @@ static PyMethodDef unicodedata_functions[] = { UNICODEDATA_INDIC_CONJUNCT_BREAK_METHODDEF UNICODEDATA_EXTENDED_PICTOGRAPHIC_METHODDEF UNICODEDATA_ITER_GRAPHEMES_METHODDEF + UNICODEDATA_ISXIDSTART_METHODDEF + UNICODEDATA_ISXIDCONTINUE_METHODDEF // The following definitions are shared between the module // and the UCD class. -#define DB_methods (unicodedata_functions + 4) +#define DB_methods (unicodedata_functions + 6) UNICODEDATA_UCD_DECIMAL_METHODDEF UNICODEDATA_UCD_DIGIT_METHODDEF @@ -2143,8 +2127,6 @@ static PyMethodDef unicodedata_functions[] = { UNICODEDATA_UCD_EAST_ASIAN_WIDTH_METHODDEF UNICODEDATA_UCD_DECOMPOSITION_METHODDEF UNICODEDATA_UCD_NAME_METHODDEF - UNICODEDATA_UCD_ISXIDSTART_METHODDEF - UNICODEDATA_UCD_ISXIDCONTINUE_METHODDEF UNICODEDATA_UCD_LOOKUP_METHODDEF UNICODEDATA_UCD_IS_NORMALIZED_METHODDEF UNICODEDATA_UCD_NORMALIZE_METHODDEF From 17d1490aa97bd6b98a42b1a9b324ead84e7fd8a2 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Mon, 19 Jan 2026 06:38:22 -0600 Subject: [PATCH 010/133] gh-143935: Email preserve parens when folding comments (#143936) Fix a bug in the folding of comments when flattening an email message using a modern email policy. Comments consisting of a very long sequence of non-foldable characters could trigger a forced line wrap that omitted the required leading space on the continuation line, causing the remainder of the comment to be interpreted as a new header field. This enabled header injection with carefully crafted inputs. Co-authored-by: Denis Ledoux --- Lib/email/_header_value_parser.py | 15 +++++++++++- .../test_email/test__header_value_parser.py | 23 +++++++++++++++++++ ...-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 +++++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py index 46fef2048ba..172f9ef9e5f 100644 --- a/Lib/email/_header_value_parser.py +++ b/Lib/email/_header_value_parser.py @@ -101,6 +101,12 @@ def make_quoted_pairs(value): return str(value).replace('\\', '\\\\').replace('"', '\\"') +def make_parenthesis_pairs(value): + """Escape parenthesis and backslash for use within a comment.""" + return str(value).replace('\\', '\\\\') \ + .replace('(', '\\(').replace(')', '\\)') + + def quote_string(value): escaped = make_quoted_pairs(value) return f'"{escaped}"' @@ -943,7 +949,7 @@ def value(self): return ' ' def startswith_fws(self): - return True + return self and self[0] in WSP class ValueTerminal(Terminal): @@ -2963,6 +2969,13 @@ def _refold_parse_tree(parse_tree, *, policy): [ValueTerminal(make_quoted_pairs(p), 'ptext') for p in newparts] + [ValueTerminal('"', 'ptext')]) + if part.token_type == 'comment': + newparts = ( + [ValueTerminal('(', 'ptext')] + + [ValueTerminal(make_parenthesis_pairs(p), 'ptext') + if p.token_type == 'ptext' else p + for p in newparts] + + [ValueTerminal(')', 'ptext')]) if not part.as_ew_allowed: wrap_as_ew_blocked += 1 newparts.append(end_ew_not_allowed) diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py index 426ec4644e3..e28fe389201 100644 --- a/Lib/test/test_email/test__header_value_parser.py +++ b/Lib/test/test_email/test__header_value_parser.py @@ -3294,6 +3294,29 @@ def test_address_list_with_specials_in_long_quoted_string(self): with self.subTest(to=to): self._test(parser.get_address_list(to)[0], folded, policy=policy) + def test_address_list_with_long_unwrapable_comment(self): + policy = self.policy.clone(max_line_length=40) + cases = [ + # (to, folded) + ('(loremipsumdolorsitametconsecteturadipi)', + '(loremipsumdolorsitametconsecteturadipi)\n'), + ('(loremipsumdolorsitametconsecteturadipi)', + '(loremipsumdolorsitametconsecteturadipi)\n'), + ('(loremipsum dolorsitametconsecteturadipi)', + '(loremipsum dolorsitametconsecteturadipi)\n'), + ('(loremipsum dolorsitametconsecteturadipi)', + '(loremipsum\n dolorsitametconsecteturadipi)\n'), + ('(Escaped \\( \\) chars \\\\ in comments stay escaped)', + '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)\n'), + ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))', + '((loremipsum)(loremipsum)(loremipsum)(loremipsum))\n'), + ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))', + '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))\n'), + ] + for (to, folded) in cases: + with self.subTest(to=to): + self._test(parser.get_address_list(to)[0], folded, policy=policy) + # XXX Need tests with comments on various sides of a unicode token, # and with unicode tokens in the comments. Spaces inside the quotes # currently don't do the right thing. diff --git a/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst new file mode 100644 index 00000000000..c3d86493688 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst @@ -0,0 +1,6 @@ +Fixed a bug in the folding of comments when flattening an email message +using a modern email policy. Comments consisting of a very long sequence of +non-foldable characters could trigger a forced line wrap that omitted the +required leading space on the continuation line, causing the remainder of +the comment to be interpreted as a new header field. This enabled header +injection with carefully crafted inputs. From 72bacb0cd0882bce6bd7e9e2e4e9c112d70213e7 Mon Sep 17 00:00:00 2001 From: Aniket <148300120+Aniketsy@users.noreply.github.com> Date: Mon, 19 Jan 2026 18:29:26 +0530 Subject: [PATCH 011/133] gh-142461: Move misplaced NEWS entries to an appropriate section (GH-143392) --- Misc/NEWS.d/3.12.0a1.rst | 24 ++++++++++++------------ Misc/NEWS.d/3.12.0a2.rst | 4 ++-- Misc/NEWS.d/3.12.0a3.rst | 4 ++-- Misc/NEWS.d/3.12.0a4.rst | 4 ++-- Misc/NEWS.d/3.12.0a5.rst | 2 +- Misc/NEWS.d/3.12.0a7.rst | 6 +++--- Misc/NEWS.d/3.12.0b1.rst | 8 ++++---- Misc/NEWS.d/3.13.0a5.rst | 4 ++-- Misc/NEWS.d/3.13.0a6.rst | 4 ++-- Misc/NEWS.d/3.13.0b1.rst | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Misc/NEWS.d/3.12.0a1.rst b/Misc/NEWS.d/3.12.0a1.rst index 0da7cdde1b2..c977022d87f 100644 --- a/Misc/NEWS.d/3.12.0a1.rst +++ b/Misc/NEWS.d/3.12.0a1.rst @@ -160,7 +160,7 @@ to calculate those doing pointer arithmetic. .. date: 2022-10-06-15-45-57 .. gh-issue: 96078 .. nonce: fS-6mU -.. section: Core and Builtins +.. section: Library :func:`os.sched_yield` now release the GIL while calling sched_yield(2). Patch by Donghee Na. @@ -170,7 +170,7 @@ Patch by Donghee Na. .. date: 2022-10-06-14-14-28 .. gh-issue: 97955 .. nonce: Nq5VXD -.. section: Core and Builtins +.. section: Library Migrate :mod:`zoneinfo` to Argument Clinic. @@ -361,7 +361,7 @@ branching conditions. .. date: 2022-09-19-03-35-01 .. gh-issue: 96821 .. nonce: izK6JA -.. section: Core and Builtins +.. section: Library Fix undefined behaviour in ``audioop.c``. @@ -481,7 +481,7 @@ Fix case of undefined behavior in ceval.c .. date: 2022-09-08-20-58-10 .. gh-issue: 64373 .. nonce: AfCi36 -.. section: Core and Builtins +.. section: Library Convert :mod:`!_functools` to argument clinic. @@ -490,7 +490,7 @@ Convert :mod:`!_functools` to argument clinic. .. date: 2022-09-07-13-38-37 .. gh-issue: 96641 .. nonce: wky0Fc -.. section: Core and Builtins +.. section: Library Do not expose ``KeyWrapper`` in :mod:`!_functools`. @@ -990,7 +990,7 @@ bytecode compiler. .. date: 2022-07-20-09-04-55 .. gh-issue: 95023 .. nonce: bs-xd7 -.. section: Core and Builtins +.. section: Library Implement :func:`os.setns` and :func:`os.unshare` for Linux. Patch by Noam Cohen. @@ -1021,7 +1021,7 @@ Previously it could cause SystemError or other undesired behavior. .. date: 2022-07-19-04-34-56 .. gh-issue: 94996 .. nonce: dV564A -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse function definitions with positional-only params when passed ``feature_version`` less than ``(3, 8)``. @@ -1041,7 +1041,7 @@ Allow jumping within, out of, and across exception handlers in the debugger. .. date: 2022-07-18-05-10-29 .. gh-issue: 94949 .. nonce: OsZ7_s -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse parenthesized context managers when passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. @@ -1051,7 +1051,7 @@ passed ``feature_version`` less than ``(3, 9)``. Patch by Shantanu Jain. .. date: 2022-07-18-04-48-34 .. gh-issue: 94947 .. nonce: df9gUw -.. section: Core and Builtins +.. section: Library :func:`ast.parse` will no longer parse assignment expressions when passed ``feature_version`` less than ``(3, 8)``. Patch by Shantanu Jain. @@ -1394,7 +1394,7 @@ calls. Previously, the end column could precede the column offset. .. date: 2022-06-09-19-19-02 .. gh-issue: 93461 .. nonce: 5DqP1e -.. section: Core and Builtins +.. section: Library :func:`importlib.invalidate_caches` now drops entries from :data:`sys.path_importer_cache` with a relative path as name. This solves a @@ -1729,7 +1729,7 @@ tracing functions implemented in C. .. date: 2022-05-11-09-16-54 .. gh-issue: 91102 .. nonce: lenv9h -.. section: Core and Builtins +.. section: Library :meth:`!_warnings.warn_explicit` is ported to Argument Clinic. @@ -1759,7 +1759,7 @@ no longer does anything. .. date: 2022-05-03-20-12-18 .. gh-issue: 92261 .. nonce: aigLnb -.. section: Core and Builtins +.. section: Library Fix hang when trying to iterate over a ``typing.Union``. diff --git a/Misc/NEWS.d/3.12.0a2.rst b/Misc/NEWS.d/3.12.0a2.rst index 20e27c0d92f..9c73ae95d10 100644 --- a/Misc/NEWS.d/3.12.0a2.rst +++ b/Misc/NEWS.d/3.12.0a2.rst @@ -333,7 +333,7 @@ aware of this shim frame and the changes to the semantics of .. date: 2022-10-19-01-01-08 .. gh-issue: 98415 .. nonce: ZS2eWh -.. section: Core and Builtins +.. section: Build Fix detection of MAC addresses for :mod:`uuid` on certain OSs. Patch by Chaim Sanders @@ -405,7 +405,7 @@ Expose :const:`~socket.ETH_P_ALL` and some of the :ref:`ETHERTYPE_* constants .. date: 2022-06-10-16-37-44 .. gh-issue: 93696 .. nonce: 65BI2R -.. section: Core and Builtins +.. section: Library Allow :mod:`pdb` to locate source for frozen modules in the standard library. diff --git a/Misc/NEWS.d/3.12.0a3.rst b/Misc/NEWS.d/3.12.0a3.rst index 04a2bf9fb91..d2c717afcb6 100644 --- a/Misc/NEWS.d/3.12.0a3.rst +++ b/Misc/NEWS.d/3.12.0a3.rst @@ -100,7 +100,7 @@ Fix bug where an :exc:`ExceptionGroup` subclass can wrap a .. date: 2022-11-16-21-35-30 .. gh-issue: 99547 .. nonce: p_c_bp -.. section: Core and Builtins +.. section: Library Add a function to os.path to check if a path is a junction: isjunction. Add similar functionality to pathlib.Path as is_junction. @@ -110,7 +110,7 @@ similar functionality to pathlib.Path as is_junction. .. date: 2022-11-12-01-39-57 .. gh-issue: 99370 .. nonce: _cu32j -.. section: Core and Builtins +.. section: Library Fix zip path for venv created from a non-installed python on POSIX platforms. diff --git a/Misc/NEWS.d/3.12.0a4.rst b/Misc/NEWS.d/3.12.0a4.rst index 57fb2052764..1fdebf54da9 100644 --- a/Misc/NEWS.d/3.12.0a4.rst +++ b/Misc/NEWS.d/3.12.0a4.rst @@ -125,7 +125,7 @@ Improve the accuracy of ``sum()`` with compensated summation. .. date: 2022-12-20-16-14-19 .. gh-issue: 100374 .. nonce: YRrVHT -.. section: Core and Builtins +.. section: Library Fix incorrect result and delay in :func:`socket.getfqdn`. Patch by Dominic Socular. @@ -315,7 +315,7 @@ Improve performance of ``list.pop`` for small lists. .. date: 2022-06-17-08-00-34 .. gh-issue: 89051 .. nonce: yP4Na0 -.. section: Core and Builtins +.. section: Library Add :const:`ssl.OP_LEGACY_SERVER_CONNECT` diff --git a/Misc/NEWS.d/3.12.0a5.rst b/Misc/NEWS.d/3.12.0a5.rst index b73bbfbfdc4..74801bf1add 100644 --- a/Misc/NEWS.d/3.12.0a5.rst +++ b/Misc/NEWS.d/3.12.0a5.rst @@ -181,7 +181,7 @@ regen-all``. .. bpo: 32780 .. date: 2018-02-05-21-54-46 .. nonce: Dtiz8z -.. section: Core and Builtins +.. section: Library Inter-field padding is now inserted into the PEP3118 format strings obtained from :class:`ctypes.Structure` objects, reflecting their true representation diff --git a/Misc/NEWS.d/3.12.0a7.rst b/Misc/NEWS.d/3.12.0a7.rst index f48b9ce0550..e0c079c5def 100644 --- a/Misc/NEWS.d/3.12.0a7.rst +++ b/Misc/NEWS.d/3.12.0a7.rst @@ -102,7 +102,7 @@ Shrink the number of inline :opcode:`CACHE` entries used by .. date: 2023-03-08-08-37-36 .. gh-issue: 102491 .. nonce: SFvvsC -.. section: Core and Builtins +.. section: Library Improve import time of ``platform`` by removing IronPython version parsing. The IronPython version parsing was not functional (see @@ -187,7 +187,7 @@ Improve build support for the Xbox. Patch by Max Bachmann. .. date: 2023-02-21-23-42-39 .. gh-issue: 102027 .. nonce: fQARG0 -.. section: Core and Builtins +.. section: Build Fix SSE2 and SSE3 detection in ``_blake2`` internal module. Patch by Max Bachmann. @@ -207,7 +207,7 @@ Deprecate ``co_lnotab`` in code objects, schedule it for removal in Python .. bpo: 1635741 .. date: 2020-07-04-09-04-41 .. nonce: ZsP31Y -.. section: Core and Builtins +.. section: Library Adapt :mod:`!_pickle` to :pep:`687`. Patch by Mohamed Koubaa and Erlend Aasland. diff --git a/Misc/NEWS.d/3.12.0b1.rst b/Misc/NEWS.d/3.12.0b1.rst index b867a4f6230..e897bfebd24 100644 --- a/Misc/NEWS.d/3.12.0b1.rst +++ b/Misc/NEWS.d/3.12.0b1.rst @@ -44,7 +44,7 @@ response to :cve:`2023-24329`. Patch by Illia Volochii. .. date: 2023-05-20-23-08-48 .. gh-issue: 102856 .. nonce: Knv9WT -.. section: Core and Builtins +.. section: Library Implement PEP 701 changes in the :mod:`tokenize` module. Patch by Marta Gómez Macías and Pablo Galindo Salgado @@ -312,7 +312,7 @@ Patch by Eric Traut, Larry Hastings, and Jelle Zijlstra. .. date: 2023-04-24-21-47-38 .. gh-issue: 103801 .. nonce: WaBanq -.. section: Core and Builtins +.. section: Library Adds three minor linting fixes to the wasm module caught that were caught by ruff. @@ -322,7 +322,7 @@ ruff. .. date: 2023-04-24-14-38-16 .. gh-issue: 103793 .. nonce: kqoH6Q -.. section: Core and Builtins +.. section: Library Optimized asyncio Task creation by deferring expensive string formatting (task name generation) from Task creation to the first time ``get_name`` is @@ -573,7 +573,7 @@ raising an :exc:`IndexError`. .. bpo: 31821 .. date: 2019-12-01-12-58-31 .. nonce: 1FNmwk -.. section: Core and Builtins +.. section: Library Fix :func:`!pause_reading` to work when called from :func:`!connection_made` in :mod:`asyncio`. diff --git a/Misc/NEWS.d/3.13.0a5.rst b/Misc/NEWS.d/3.13.0a5.rst index 19ba16bc8c8..6f8c82e5af3 100644 --- a/Misc/NEWS.d/3.13.0a5.rst +++ b/Misc/NEWS.d/3.13.0a5.rst @@ -136,7 +136,7 @@ threads to be interrupted. .. date: 2024-02-08-16-01-18 .. gh-issue: 115154 .. nonce: ji96FV -.. section: Core and Builtins +.. section: Library Fix a bug that was causing the :func:`tokenize.untokenize` function to handle unicode named literals incorrectly. Patch by Pablo Galindo @@ -156,7 +156,7 @@ Add ability to force alignment of :mod:`ctypes.Structure` by way of the new .. date: 2023-07-16-15-02-47 .. gh-issue: 104090 .. nonce: oMjNa9 -.. section: Core and Builtins +.. section: Library The multiprocessing resource tracker now exits with non-zero status code if a resource leak was detected. It still exits with status code 0 otherwise. diff --git a/Misc/NEWS.d/3.13.0a6.rst b/Misc/NEWS.d/3.13.0a6.rst index ad6622d23bf..b97973fad02 100644 --- a/Misc/NEWS.d/3.13.0a6.rst +++ b/Misc/NEWS.d/3.13.0a6.rst @@ -224,7 +224,7 @@ When the collecting space becomes empty, the two spaces are swapped. .. date: 2023-10-14-00-05-17 .. gh-issue: 109870 .. nonce: oKpJ3P -.. section: Core and Builtins +.. section: Library Dataclasses now calls :func:`exec` once per dataclass, instead of once per method being added. This can speed up dataclass creation by up to 20%. @@ -234,7 +234,7 @@ method being added. This can speed up dataclass creation by up to 20%. .. date: 2022-10-05-09-33-48 .. gh-issue: 97901 .. nonce: BOLluU -.. section: Core and Builtins +.. section: Library Mime type ``text/rtf`` is now supported by :mod:`mimetypes`. diff --git a/Misc/NEWS.d/3.13.0b1.rst b/Misc/NEWS.d/3.13.0b1.rst index 97731276679..d0eef2d8c11 100644 --- a/Misc/NEWS.d/3.13.0b1.rst +++ b/Misc/NEWS.d/3.13.0b1.rst @@ -60,7 +60,7 @@ for speed. .. date: 2024-05-03-18-01-26 .. gh-issue: 95382 .. nonce: 73FSEv -.. section: Core and Builtins +.. section: Library Improve performance of :func:`json.dumps` and :func:`json.dump` when using the argument *indent*. Depending on the data the encoding using From 375e372c6661d818b85d1405c5ba681a06988ebd Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Mon, 19 Jan 2026 22:09:30 +0800 Subject: [PATCH 012/133] gh-143689: Fix BufferedReader.read1 leaving object in reentrant state on error (#143690) BufferedReader.read1() could leave the buffered object in a reentrant (locked) state when an exception was raised while allocating the output buffer. This change ensures the internal buffered lock is always released on error, keeping the object in a consistent state after failures. Signed-off-by: Yongtao Huang Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Cody Maloney Co-authored-by: sobolevn --- Lib/test/test_io/test_bufferedio.py | 21 ++++++++++++++++++- ...-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst | 1 + Modules/_io/bufferedio.c | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst diff --git a/Lib/test/test_io/test_bufferedio.py b/Lib/test/test_io/test_bufferedio.py index 3278665bdc9..e83dd0d4e28 100644 --- a/Lib/test/test_io/test_bufferedio.py +++ b/Lib/test/test_io/test_bufferedio.py @@ -10,7 +10,7 @@ from collections import deque, UserList from itertools import cycle, count from test import support -from test.support import os_helper, threading_helper +from test.support import check_sanitizer, os_helper, threading_helper from .utils import byteslike, CTestCase, PyTestCase @@ -623,6 +623,25 @@ def test_bad_readinto_type(self): bufio.readline() self.assertIsInstance(cm.exception.__cause__, TypeError) + @unittest.skipUnless(sys.maxsize > 2**32, 'requires 64bit platform') + @unittest.skipIf(check_sanitizer(thread=True), + 'ThreadSanitizer aborts on huge allocations (exit code 66).') + def test_read1_error_does_not_cause_reentrant_failure(self): + self.addCleanup(os_helper.unlink, os_helper.TESTFN) + with self.open(os_helper.TESTFN, "wb") as f: + f.write(b"hello") + + with self.open(os_helper.TESTFN, "rb", buffering=0) as raw: + bufio = self.tp(raw, buffer_size=8) + # To request a size that is far too huge to ever be satisfied, + # so that the internal buffer allocation reliably fails with MemoryError. + huge = sys.maxsize // 2 + 1 + with self.assertRaises(MemoryError): + bufio.read1(huge) + + # Used to crash before gh-143689: + self.assertEqual(bufio.read1(1), b"h") + class PyBufferedReaderTest(BufferedReaderTest, PyTestCase): tp = pyio.BufferedReader diff --git a/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst b/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst new file mode 100644 index 00000000000..a423b1b70ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-11-14-14-19.gh-issue-143689.fzHJ2W.rst @@ -0,0 +1 @@ +Fix :meth:`io.BufferedReader.read1` state cleanup on buffer allocation failure. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 4602f2b42a6..6d779abd89c 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1073,6 +1073,7 @@ _io__Buffered_read1_impl(buffered *self, Py_ssize_t n) PyBytesWriter *writer = PyBytesWriter_Create(n); if (writer == NULL) { + LEAVE_BUFFERED(self) return NULL; } From 3c9c3d33cbdef257526871cbc12e93635026f5d6 Mon Sep 17 00:00:00 2001 From: Adorilson Bezerra Date: Mon, 19 Jan 2026 14:15:55 +0000 Subject: [PATCH 013/133] gh-106318: Add examples for str.rpartition() method (#143891) --- Doc/library/stdtypes.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 22bc1536c1a..ce0d7cbb2e4 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2562,6 +2562,19 @@ expression support in the :mod:`re` module). after the separator. If the separator is not found, return a 3-tuple containing two empty strings, followed by the string itself. + For example: + + .. doctest:: + + >>> 'Monty Python'.rpartition(' ') + ('Monty', ' ', 'Python') + >>> "Monty Python's Flying Circus".rpartition(' ') + ("Monty Python's Flying", ' ', 'Circus') + >>> 'Monty Python'.rpartition('-') + ('', '', 'Monty Python') + + See also :meth:`partition`. + .. method:: str.rsplit(sep=None, maxsplit=-1) From f84ea1107170988742fbd350123678a5c503c1ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Mon, 19 Jan 2026 18:36:55 +0100 Subject: [PATCH 014/133] gh-102809: No longer mention `Misc/gdbinit` in the code (#143980) Fix misleading comment on `PyObject_Dump`. --- Objects/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/object.c b/Objects/object.c index ea42990e69b..649b109d5cb 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -711,7 +711,7 @@ _PyObject_IsFreed(PyObject *op) } -/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ +/* For debugging convenience. */ void PyObject_Dump(PyObject* op) { From e66597d6c84a8615340822b8da564e5ca3fba5cd Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Tue, 20 Jan 2026 08:11:07 +0800 Subject: [PATCH 015/133] gh-143874: Use self.message instead of raw print in `_exec_in_closure()` (#143875) --- Lib/pdb.py | 2 +- Lib/test/test_remote_pdb.py | 28 +++++++++++++++++++ ...-01-15-16-04-39.gh-issue-143874.1qQgvo.rst | 1 + 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-15-16-04-39.gh-issue-143874.1qQgvo.rst diff --git a/Lib/pdb.py b/Lib/pdb.py index 0464b288ef8..b5d8f827827 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -888,7 +888,7 @@ def _exec_in_closure(self, source, globals, locals): locals.update(pdb_eval["write_back"]) eval_result = pdb_eval["result"] if eval_result is not None: - print(repr(eval_result)) + self.message(repr(eval_result)) return True diff --git a/Lib/test/test_remote_pdb.py b/Lib/test/test_remote_pdb.py index ede99de9819..d26d63faa61 100644 --- a/Lib/test/test_remote_pdb.py +++ b/Lib/test/test_remote_pdb.py @@ -1441,6 +1441,34 @@ def test_multi_line_commands(self): self.assertIn("Function returned: 42", stdout) self.assertEqual(process.returncode, 0) + def test_exec_in_closure_result_uses_pdb_stdout(self): + """ + Expression results executed via _exec_in_closure() should be written + to the debugger output stream (pdb stdout), not to sys.stdout. + """ + self._create_script() + process, client_file = self._connect_and_get_client_file() + + with kill_on_error(process): + self._read_until_prompt(client_file) + + self._send_command(client_file, "(lambda: 123)()") + messages = self._read_until_prompt(client_file) + result_msg = "".join(msg.get("message", "") for msg in messages) + self.assertIn("123", result_msg) + + self._send_command(client_file, "sum(i for i in (1, 2, 3))") + messages = self._read_until_prompt(client_file) + result_msg = "".join(msg.get("message", "") for msg in messages) + self.assertIn("6", result_msg) + + self._send_command(client_file, "c") + stdout, _ = process.communicate(timeout=SHORT_TIMEOUT) + + self.assertNotIn("\n123\n", stdout) + self.assertNotIn("\n6\n", stdout) + self.assertEqual(process.returncode, 0) + def _supports_remote_attaching(): PROCESS_VM_READV_SUPPORTED = False diff --git a/Misc/NEWS.d/next/Library/2026-01-15-16-04-39.gh-issue-143874.1qQgvo.rst b/Misc/NEWS.d/next/Library/2026-01-15-16-04-39.gh-issue-143874.1qQgvo.rst new file mode 100644 index 00000000000..a11cf715b04 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-15-16-04-39.gh-issue-143874.1qQgvo.rst @@ -0,0 +1 @@ +Fixed a bug in :mod:`pdb` where expression results were not sent back to remote client. From 05eab964350dc1b4c04352c87fff4904d324b7ca Mon Sep 17 00:00:00 2001 From: Bodhi Silberling Date: Mon, 19 Jan 2026 22:50:34 -0800 Subject: [PATCH 016/133] Fix typo: 'exept' -> 'except' in Lib/dbm/dumb.py (GH-144060) --- Lib/dbm/dumb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/dbm/dumb.py b/Lib/dbm/dumb.py index 1bc239a84ff..c1c38da5101 100644 --- a/Lib/dbm/dumb.py +++ b/Lib/dbm/dumb.py @@ -9,7 +9,7 @@ - seems to contain a bug when updating... - reclaim free space (currently, space once occupied by deleted or expanded -items is not reused exept if .reorganize() is called) +items is not reused except if .reorganize() is called) - support concurrent access (currently, if two processes take turns making updates, they can mess up the index) From 71cbffde61449a224dffcae937f5f6be4f86ad09 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 20 Jan 2026 09:16:36 +0200 Subject: [PATCH 017/133] gh-143754: Add Tkinter methods pack_content(), place_content() and grid_content() (GH-143845) They use Tk commands with new name like "pack content instead of old "pack slaves". --- Doc/whatsnew/3.15.rst | 6 ++ .../test_tkinter/test_geometry_managers.py | 66 ++++++++++++++----- Lib/tkinter/__init__.py | 46 ++++++++++++- ...-01-14-20-35-40.gh-issue-143754.m2NQXA.rst | 3 + 4 files changed, 102 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index b7a27d5db63..1dd66065b0f 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -792,6 +792,12 @@ tkinter using Tcl's ``-all`` and ``-overlap`` options. (Contributed by Rihaan Meher in :gh:`130848`) +* Added new methods :meth:`!pack_content`, :meth:`!place_content` and + :meth:`!grid_content` which use Tk commands with new names (introduced + in Tk 8.6) instead of :meth:`!*_slaves` methods which use Tk commands + with outdated names. + (Contributed by Serhiy Storchaka in :gh:`143754`) + types ------ diff --git a/Lib/test/test_tkinter/test_geometry_managers.py b/Lib/test/test_tkinter/test_geometry_managers.py index b2ce143ff09..3dcdadd1aac 100644 --- a/Lib/test/test_tkinter/test_geometry_managers.py +++ b/Lib/test/test_tkinter/test_geometry_managers.py @@ -40,11 +40,11 @@ def test_pack_configure_after(self): b.pack_configure(side='top') c.pack_configure(side='top') d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + self.assertEqual(pack.pack_content(), [a, b, c, d]) a.pack_configure(after=b) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + self.assertEqual(pack.pack_content(), [b, a, c, d]) a.pack_configure(after=a) - self.assertEqual(pack.pack_slaves(), [b, a, c, d]) + self.assertEqual(pack.pack_content(), [b, a, c, d]) def test_pack_configure_anchor(self): pack, a, b, c, d = self.create2() @@ -73,11 +73,11 @@ def test_pack_configure_before(self): b.pack_configure(side='top') c.pack_configure(side='top') d.pack_configure(side='top') - self.assertEqual(pack.pack_slaves(), [a, b, c, d]) + self.assertEqual(pack.pack_content(), [a, b, c, d]) a.pack_configure(before=d) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + self.assertEqual(pack.pack_content(), [b, c, a, d]) a.pack_configure(before=a) - self.assertEqual(pack.pack_slaves(), [b, c, a, d]) + self.assertEqual(pack.pack_content(), [b, c, a, d]) def test_pack_configure_expand(self): pack, a, b, c, d = self.create2() @@ -110,10 +110,10 @@ def test_pack_configure_in(self): c.pack_configure(side='top') d.pack_configure(side='top') a.pack_configure(in_=pack) - self.assertEqual(pack.pack_slaves(), [b, c, d, a]) + self.assertEqual(pack.pack_content(), [b, c, d, a]) a.pack_configure(in_=c) - self.assertEqual(pack.pack_slaves(), [b, c, d]) - self.assertEqual(c.pack_slaves(), [a]) + self.assertEqual(pack.pack_content(), [b, c, d]) + self.assertEqual(c.pack_content(), [a]) with self.assertRaisesRegex( TclError, """can't pack "?%s"? inside itself""" % (a,)): a.pack_configure(in_=a) @@ -223,11 +223,11 @@ def test_pack_forget(self): a.pack_configure() b.pack_configure() c.pack_configure() - self.assertEqual(pack.pack_slaves(), [a, b, c]) + self.assertEqual(pack.pack_content(), [a, b, c]) b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) + self.assertEqual(pack.pack_content(), [a, c]) b.pack_forget() - self.assertEqual(pack.pack_slaves(), [a, c]) + self.assertEqual(pack.pack_content(), [a, c]) d.pack_forget() def test_pack_info(self): @@ -273,6 +273,14 @@ def test_pack_propagate(self): self.assertEqual(pack.winfo_reqwidth(), 20) self.assertEqual(pack.winfo_reqheight(), 40) + def test_pack_content(self): + pack, a, b, c, d = self.create2() + self.assertEqual(pack.pack_content(), []) + a.pack_configure() + self.assertEqual(pack.pack_content(), [a]) + b.pack_configure() + self.assertEqual(pack.pack_content(), [a, b]) + def test_pack_slaves(self): pack, a, b, c, d = self.create2() self.assertEqual(pack.pack_slaves(), []) @@ -477,6 +485,15 @@ def test_place_info(self): with self.assertRaises(TypeError): f2.place_info(0) + def test_place_content(self): + foo = tkinter.Frame(self.root) + bar = tkinter.Frame(self.root) + self.assertEqual(foo.place_content(), []) + bar.place_configure(in_=foo) + self.assertEqual(foo.place_content(), [bar]) + with self.assertRaises(TypeError): + foo.place_content(0) + def test_place_slaves(self): foo = tkinter.Frame(self.root) bar = tkinter.Frame(self.root) @@ -729,10 +746,10 @@ def test_grid_forget(self): c = tkinter.Button(self.root) b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) + self.assertEqual(self.root.grid_content(), [b]) b.grid_forget() c.grid_forget() - self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(self.root.grid_content(), []) self.assertEqual(b.grid_info(), {}) b.grid_configure(row=0, column=0) info = b.grid_info() @@ -749,10 +766,10 @@ def test_grid_remove(self): c = tkinter.Button(self.root) b.grid_configure(row=2, column=2, rowspan=2, columnspan=2, padx=3, pady=4, sticky='ns') - self.assertEqual(self.root.grid_slaves(), [b]) + self.assertEqual(self.root.grid_content(), [b]) b.grid_remove() c.grid_remove() - self.assertEqual(self.root.grid_slaves(), []) + self.assertEqual(self.root.grid_content(), []) self.assertEqual(b.grid_info(), {}) b.grid_configure(row=0, column=0) info = b.grid_info() @@ -887,6 +904,23 @@ def test_grid_size(self): f.grid_configure(row=4, column=5) self.assertEqual(self.root.grid_size(), (6, 5)) + def test_grid_content(self): + self.assertEqual(self.root.grid_content(), []) + a = tkinter.Label(self.root) + a.grid_configure(row=0, column=1) + b = tkinter.Label(self.root) + b.grid_configure(row=1, column=0) + c = tkinter.Label(self.root) + c.grid_configure(row=1, column=1) + d = tkinter.Label(self.root) + d.grid_configure(row=1, column=1) + self.assertEqual(self.root.grid_content(), [d, c, b, a]) + self.assertEqual(self.root.grid_content(row=0), [a]) + self.assertEqual(self.root.grid_content(row=1), [d, c, b]) + self.assertEqual(self.root.grid_content(column=0), [b]) + self.assertEqual(self.root.grid_content(column=1), [d, c, a]) + self.assertEqual(self.root.grid_content(row=1, column=1), [d, c]) + def test_grid_slaves(self): self.assertEqual(self.root.grid_slaves(), []) a = tkinter.Label(self.root) diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index be150e2b892..d695e3ec9cb 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1885,9 +1885,21 @@ def pack_propagate(self, flag=_noarg_): propagate = pack_propagate - def pack_slaves(self): + def pack_content(self): """Returns a list of all of the content widgets in the packing order for this container.""" + try: + res = self.tk.call('pack', 'content', self._w) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('pack', 'slaves', self._w) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + content = pack_content + + def pack_slaves(self): + """Synonym for pack_content().""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call('pack', 'slaves', self._w))] @@ -1895,9 +1907,19 @@ def pack_slaves(self): slaves = pack_slaves # Place method that applies to the container widget - def place_slaves(self): + def place_content(self): """Returns a list of all the content widgets for which this widget is the container.""" + try: + res = self.tk.call('place', 'content', self._w) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('place', 'slaves', self._w) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + def place_slaves(self): + """Synonym for place_content().""" return [self._nametowidget(x) for x in self.tk.splitlist( self.tk.call( @@ -2018,7 +2040,7 @@ def grid_size(self): size = grid_size - def grid_slaves(self, row=None, column=None): + def grid_content(self, row=None, column=None): """Returns a list of the content widgets. If no arguments are supplied, a list of all of the content in this @@ -2027,6 +2049,21 @@ def grid_slaves(self, row=None, column=None): column is returned. """ args = () + if row is not None: + args = args + ('-row', row) + if column is not None: + args = args + ('-column', column) + try: + res = self.tk.call('grid', 'content', self._w, *args) + except TclError: + if self.info_patchlevel() >= (8, 6): + raise + res = self.tk.call('grid', 'slaves', self._w, *args) + return [self._nametowidget(x) for x in self.tk.splitlist(res)] + + def grid_slaves(self, row=None, column=None): + """Synonym for grid_content().""" + args = () if row is not None: args = args + ('-row', row) if column is not None: @@ -2641,6 +2678,7 @@ def pack_info(self): info = pack_info propagate = pack_propagate = Misc.pack_propagate + content = pack_content = Misc.pack_content slaves = pack_slaves = Misc.pack_slaves @@ -2698,6 +2736,7 @@ def place_info(self): return d info = place_info + content = place_content = Misc.place_content slaves = place_slaves = Misc.place_slaves @@ -2753,6 +2792,7 @@ def grid_info(self): propagate = grid_propagate = Misc.grid_propagate rowconfigure = grid_rowconfigure = Misc.grid_rowconfigure size = grid_size = Misc.grid_size + content = grid_content = Misc.grid_content slaves = grid_slaves = Misc.grid_slaves diff --git a/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst b/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst new file mode 100644 index 00000000000..edfdd109400 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-14-20-35-40.gh-issue-143754.m2NQXA.rst @@ -0,0 +1,3 @@ +Add new :mod:`tkinter` widget methods :meth:`!pack_content`, +:meth:`!place_content` and :meth:`!grid_content` which are alternative +spelling of old :meth:`!*_slaves` methods. From fa3abf5a51d42b2d62e1bc89e9465b398a567e94 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Tue, 20 Jan 2026 04:07:29 -0500 Subject: [PATCH 018/133] gh-143774 - Improve IDLE Format Paragraph doc (#143775) Add a reminder to not rewrap code line to the Menu => Format => Reformat Paragraph entry. In Editing and Nagivagion, add a new 'Format block' subsection that defines 'paragraph' to better match what is dependably handled as more or less expected. In particular, specify equal indents and that the resulting indent equals original indent. Also mention that selections are expanded to complete lines and how to modify max length. (Also fix a couple case errors in cross references.) --- Doc/library/idle.rst | 24 ++++++++++++++---- Lib/idlelib/help.html | 25 +++++++++++++------ ...-01-13-01-21-20.gh-issue-143774.rqGwX1.rst | 1 + 3 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst diff --git a/Doc/library/idle.rst b/Doc/library/idle.rst index a16f46ef812..89be225b6ba 100644 --- a/Doc/library/idle.rst +++ b/Doc/library/idle.rst @@ -158,7 +158,7 @@ Go to Line Show Completions Open a scrollable list allowing selection of existing names. See - :ref:`Completions ` in the Editing and navigation section below. + :ref:`Completions ` in the Editing and Navigation section below. Expand Word Expand a prefix you have typed to match a full word in the same window; @@ -167,7 +167,7 @@ Expand Word Show Call Tip After an unclosed parenthesis for a function, open a small window with function parameter hints. See :ref:`Calltips ` in the - Editing and navigation section below. + Editing and Navigation section below. Show Surrounding Parens Highlight the surrounding parenthesis. @@ -178,9 +178,9 @@ Format menu (Editor window only) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Format Paragraph - Reformat the current blank-line-delimited paragraph in comment block or - multiline string or selected line in a string. All lines in the - paragraph will be formatted to less than N columns, where N defaults to 72. + Rewrap the text block containing the text insert cursor. + Avoid code lines. See :ref:`Format block` in the + Editing and Navigation section below. Indent Region Shift selected lines right by the indent width (default 4 spaces). @@ -566,6 +566,20 @@ In an editor, import statements have no effect until one runs the file. One might want to run a file after writing import statements, after adding function definitions, or after opening an existing file. +.. _format-block: + +Format block +^^^^^^^^^^^^ + +Reformat Paragraph rewraps a block ('paragraph') of contiguous equally +indented non-blank comments, a similar block of text within a multiline +string, or a selected subset of either. +If needed, add a blank line to separate string from code. +Partial lines in a selection expand to complete lines. +The resulting lines have the same indent as before +but have maximum total length of N columns (characters). +Change the default N of 72 on the Window tab of IDLE Settings. + .. _code-context: Code Context diff --git a/Lib/idlelib/help.html b/Lib/idlelib/help.html index 9eb18d8f39b..eda16ac5bed 100644 --- a/Lib/idlelib/help.html +++ b/Lib/idlelib/help.html @@ -111,14 +111,14 @@ line visible. A request past the end of the file goes to the end. Clear any selection and update the line and column status.

Show Completions

Open a scrollable list allowing selection of existing names. See -Completions in the Editing and navigation section below.

+Completions in the Editing and Navigation section below.

Expand Word

Expand a prefix you have typed to match a full word in the same window; repeat to get a different expansion.

Show Call Tip

After an unclosed parenthesis for a function, open a small window with function parameter hints. See Calltips in the -Editing and navigation section below.

+Editing and Navigation section below.

Show Surrounding Parens

Highlight the surrounding parenthesis.

@@ -127,9 +127,9 @@ Editing and navigation section below.

Format menu (Editor window only)

-
Format Paragraph

Reformat the current blank-line-delimited paragraph in comment block or -multiline string or selected line in a string. All lines in the -paragraph will be formatted to less than N columns, where N defaults to 72.

+
Format Paragraph

Rewrap the text block containing the text insert cursor. +Avoid code lines. See Format block in the +Editing and Navigation section below.

Indent Region

Shift selected lines right by the indent width (default 4 spaces).

@@ -443,8 +443,19 @@ will display a calltip.

One might want to run a file after writing import statements, after adding function definitions, or after opening an existing file.

+
+

Format block

+

Reformat Paragraph rewraps a block (‘paragraph’) of contiguous equally +indented non-blank comments, a similar block of text within a multiline +string, or a selected subset of either. +If needed, add a blank line to separate string from code. +Partial lines in a selection expand to complete lines. +The resulting lines have the same indent as before +but have maximum total length of N columns (characters). +Change the default N of 72 on the Window tab of IDLE Settings.

+
-

Code Context

+

Code Context

Within an editor window containing Python code, code context can be toggled in order to show or hide a pane at the top of the window. When shown, this pane freezes the opening lines for block code, such as those beginning with @@ -791,7 +802,7 @@ with the default subprocess if at all possible.

Help and Preferences

-

Help sources

+

Help sources

Help menu entry “IDLE Help” displays a formatted html version of the IDLE chapter of the Library Reference. The result, in a read-only tkinter text window, is close to what one sees in a web browser. diff --git a/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst b/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst new file mode 100644 index 00000000000..dd15d1672b1 --- /dev/null +++ b/Misc/NEWS.d/next/IDLE/2026-01-13-01-21-20.gh-issue-143774.rqGwX1.rst @@ -0,0 +1 @@ +Better explain the operation of Format / Format Paragraph. From fa44efa0ef1972ac1e2f66996303154be11f605e Mon Sep 17 00:00:00 2001 From: AZero13 Date: Tue, 20 Jan 2026 04:50:51 -0500 Subject: [PATCH 019/133] gh-144023: Prevent follow_symlinks from being allowed with an fd of 0 (GH-144022) The check was (fd > 0), should be (fd >= 0). --- Lib/test/test_os/test_posix.py | 12 ++++++++++++ .../2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst | 2 ++ Modules/posixmodule.c | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst diff --git a/Lib/test/test_os/test_posix.py b/Lib/test/test_os/test_posix.py index 37da293a441..995c48bdbbf 100644 --- a/Lib/test/test_os/test_posix.py +++ b/Lib/test/test_os/test_posix.py @@ -668,6 +668,18 @@ def test_fstat(self): finally: fp.close() + @unittest.skipUnless(hasattr(posix, 'stat'), + 'test needs posix.stat()') + @unittest.skipUnless(os.stat in os.supports_follow_symlinks, + 'test needs follow_symlinks support in os.stat()') + def test_stat_fd_zero_follow_symlinks(self): + with self.assertRaisesRegex(ValueError, + 'cannot use fd and follow_symlinks together'): + posix.stat(0, follow_symlinks=False) + with self.assertRaisesRegex(ValueError, + 'cannot use fd and follow_symlinks together'): + posix.stat(1, follow_symlinks=False) + def check_statlike_path(self, func): self.assertTrue(func(os_helper.TESTFN)) self.assertTrue(func(os.fsencode(os_helper.TESTFN))) diff --git a/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst b/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst new file mode 100644 index 00000000000..0d06506e1ec --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-19-00-57-40.gh-issue-144023.29XUcp.rst @@ -0,0 +1,2 @@ +Fixed validation of file descriptor 0 in posix functions when used with +follow_symlinks parameter. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 49214d57a2e..ef90ac5de09 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -1637,7 +1637,7 @@ static int fd_and_follow_symlinks_invalid(const char *function_name, int fd, int follow_symlinks) { - if ((fd > 0) && (!follow_symlinks)) { + if ((fd >= 0) && (!follow_symlinks)) { PyErr_Format(PyExc_ValueError, "%s: cannot use fd and follow_symlinks together", function_name); From 76b484b9d16d6a3b1749dc89d99773b5b4a5c4a5 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Tue, 20 Jan 2026 18:20:06 +0800 Subject: [PATCH 020/133] gh-143999: Fix: handle suspended state on types.coroutine wrappers (GH-144000) --- Lib/test/test_inspect/test_inspect.py | 24 +++++++++++++++++++ Lib/types.py | 4 ++++ ...-01-18-14-35-37.gh-issue-143999.MneN4O.rst | 1 + 3 files changed, 29 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index b25414bea65..1999aa770ec 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -2804,6 +2804,30 @@ def running_check_generator(): # Running after the first yield next(self.generator) + def test_types_coroutine_wrapper_state(self): + def gen(): + yield 1 + yield 2 + + @types.coroutine + def wrapped_generator_coro(): + # return a generator iterator so types.coroutine + # wraps it into types._GeneratorWrapper. + return gen() + + g = wrapped_generator_coro() + self.addCleanup(g.close) + self.assertIs(type(g), types._GeneratorWrapper) + + # _GeneratorWrapper must provide gi_suspended/cr_suspended + # so inspect.get*state() doesn't raise AttributeError. + self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_CREATED) + self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_CREATED) + + next(g) + self.assertEqual(inspect.getgeneratorstate(g), inspect.GEN_SUSPENDED) + self.assertEqual(inspect.getcoroutinestate(g), inspect.CORO_SUSPENDED) + def test_easy_debugging(self): # repr() and str() of a generator state should contain the state name names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split() diff --git a/Lib/types.py b/Lib/types.py index f96c75b46da..73a69c40c8d 100644 --- a/Lib/types.py +++ b/Lib/types.py @@ -276,10 +276,14 @@ def gi_running(self): @property def gi_yieldfrom(self): return self.__wrapped.gi_yieldfrom + @property + def gi_suspended(self): + return self.__wrapped.gi_suspended cr_code = gi_code cr_frame = gi_frame cr_running = gi_running cr_await = gi_yieldfrom + cr_suspended = gi_suspended def __next__(self): return next(self.__wrapped) def __iter__(self): diff --git a/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst new file mode 100644 index 00000000000..dc87411aacc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-18-14-35-37.gh-issue-143999.MneN4O.rst @@ -0,0 +1 @@ +Fix an issue where :func:`inspect.getgeneratorstate` and :func:`inspect.getcoroutinestate` could fail for generators wrapped by :func:`types.coroutine` in the suspended state. From fe629262c0db7aa18bad8bf3ac524acd8695739b Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 <148854295+VanshAgarwal24036@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:35:42 +0530 Subject: [PATCH 021/133] gh-144050: Fix stat.filemode pure Python file type detection (GH-144059) --- Lib/stat.py | 11 ++++++++--- Lib/test/test_stat.py | 5 +++++ .../2026-01-20-16-35-55.gh-issue-144050.0kKFbF.rst | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-20-16-35-55.gh-issue-144050.0kKFbF.rst diff --git a/Lib/stat.py b/Lib/stat.py index ab1b25b9d63..214c7917b5e 100644 --- a/Lib/stat.py +++ b/Lib/stat.py @@ -166,9 +166,14 @@ def filemode(mode): perm = [] for index, table in enumerate(_filemode_table): for bit, char in table: - if mode & bit == bit: - perm.append(char) - break + if index == 0: + if S_IFMT(mode) == bit: + perm.append(char) + break + else: + if mode & bit == bit: + perm.append(char) + break else: if index == 0: # Unknown filetype diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py index 5fd25d5012c..a83f7d076f0 100644 --- a/Lib/test/test_stat.py +++ b/Lib/test/test_stat.py @@ -163,6 +163,11 @@ def test_mode(self): self.statmod.S_IFREG) self.assertEqual(self.statmod.S_IMODE(st_mode), 0o666) + def test_filemode_does_not_misclassify_random_bits(self): + # gh-144050 regression test + self.assertEqual(self.statmod.filemode(0o77777)[0], "?") + self.assertEqual(self.statmod.filemode(0o177777)[0], "?") + @os_helper.skip_unless_working_chmod def test_directory(self): os.mkdir(TESTFN) diff --git a/Misc/NEWS.d/next/Library/2026-01-20-16-35-55.gh-issue-144050.0kKFbF.rst b/Misc/NEWS.d/next/Library/2026-01-20-16-35-55.gh-issue-144050.0kKFbF.rst new file mode 100644 index 00000000000..dfc062d023c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-20-16-35-55.gh-issue-144050.0kKFbF.rst @@ -0,0 +1,2 @@ +Fix :func:`stat.filemode` in the pure-Python implementation to avoid misclassifying +invalid mode values as block devices. From 31c81ab0a2fb7009a76426617991a9b539ab0180 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Tue, 20 Jan 2026 15:09:20 +0300 Subject: [PATCH 022/133] Update struct.__doc__: _Bool available unconditionally (#143716) This amends commit a9296e7f3be4d6c22271b25c86467ff867c63bbb. --- Modules/_struct.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index c3f8359ac39..74ae9e4c33d 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2662,8 +2662,7 @@ The optional first format char indicates byte order, size and alignment:\n\ The remaining chars indicate types of args and must match exactly;\n\ these can be preceded by a decimal repeat count:\n\ x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\ - ?: _Bool (requires C99; if not available, char is used instead)\n\ - h:short; H:unsigned short; i:int; I:unsigned int;\n\ + ?:_Bool; h:short; H:unsigned short; i:int; I:unsigned int;\n\ l:long; L:unsigned long; f:float; d:double; e:half-float.\n\ F:float complex; D:double complex.\n\ Special cases (preceding decimal count indicates length):\n\ From 795d5c5b44c5ac4b7d1619800f341ec2d0332430 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Tue, 20 Jan 2026 05:45:12 -0800 Subject: [PATCH 023/133] gh-144054: shutdown fix for deferred ref counting (GH-144055) When shutting down, disable deferred refcounting for all GC objects. It is important to do this also for untracked objects, which before this change were getting missed. Small code cleanup: We can remove the shutdown case disable_deferred_refcounting() call inside scan_heap_visitor() if we are careful about it. The key is that frame_disable_deferred_refcounting() might fail if the object is untracked. --- Python/gc_free_threading.c | 52 +++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 51261cea0cf..beb3fa588f4 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -308,17 +308,18 @@ disable_deferred_refcounting(PyObject *op) // should also be disabled when we turn off deferred refcounting. _PyObject_DisablePerThreadRefcounting(op); } - - // Generators and frame objects may contain deferred references to other - // objects. If the pointed-to objects are part of cyclic trash, we may - // have disabled deferred refcounting on them and need to ensure that we - // use strong references, in case the generator or frame object is - // resurrected by a finalizer. - if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) { - frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe); - } - else if (PyFrame_Check(op)) { - frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame); + if (_PyObject_GC_IS_TRACKED(op)) { + // Generators and frame objects may contain deferred references to other + // objects. If the pointed-to objects are part of cyclic trash, we may + // have disabled deferred refcounting on them and need to ensure that we + // use strong references, in case the generator or frame object is + // resurrected by a finalizer. + if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) { + frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe); + } + else if (PyFrame_Check(op)) { + frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame); + } } } @@ -1240,19 +1241,30 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, return true; } - if (state->reason == _Py_GC_REASON_SHUTDOWN) { - // Disable deferred refcounting for reachable objects as well during - // interpreter shutdown. This ensures that these objects are collected - // immediately when their last reference is removed. - disable_deferred_refcounting(op); - } - // object is reachable, restore `ob_tid`; we're done with these objects gc_restore_tid(op); gc_clear_alive(op); return true; } +// Disable deferred refcounting for reachable objects during interpreter +// shutdown. This ensures that these objects are collected immediately when +// their last reference is removed. This needs to consider both tracked and +// untracked GC objects, since either might have deferred refcounts enabled. +static bool +scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area, + void *block, size_t block_size, void *args) +{ + PyObject *op = op_from_block_all_gc(block, args); + if (op == NULL) { + return true; + } + if (!_Py_IsImmortal(op)) { + disable_deferred_refcounting(op); + } + return true; +} + static int move_legacy_finalizer_reachable(struct collection_state *state); @@ -1487,6 +1499,10 @@ deduce_unreachable_heap(PyInterpreterState *interp, // Restores ob_tid for reachable objects. gc_visit_heaps(interp, &scan_heap_visitor, &state->base); + if (state->reason == _Py_GC_REASON_SHUTDOWN) { + gc_visit_heaps(interp, &scan_heap_disable_deferred, &state->base); + } + if (state->legacy_finalizers.head) { // There may be objects reachable from legacy finalizers that are in // the unreachable set. We need to mark them as reachable. From a126893fa80c4ee5f0bac8a84a49491c19edd511 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 20 Jan 2026 17:25:31 +0200 Subject: [PATCH 024/133] gh-143960: Add support for OpenSSL 3.6, drop EOL 3.2 (#143961) Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- ...-01-17-15-31-19.gh-issue-143960.Zi0EqR.rst | 1 + Modules/_ssl.c | 2 +- Modules/{_ssl_data_35.h => _ssl_data_36.h} | 24 +++++++++++++++++-- Tools/ssl/make_ssl_data.py | 4 ++-- Tools/ssl/multissltests.py | 3 ++- 6 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-01-17-15-31-19.gh-issue-143960.Zi0EqR.rst rename Modules/{_ssl_data_35.h => _ssl_data_36.h} (99%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2dc610ce37c..e7f7aa5172e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -261,7 +261,7 @@ jobs: # Keep 1.1.1w in our list despite it being upstream EOL and otherwise # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs # supported by important vendors such as AWS-LC. - openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4] + openssl_ver: [1.1.1w, 3.0.18, 3.3.5, 3.4.3, 3.5.4, 3.6.0] # See Tools/ssl/make_ssl_data.py for notes on adding a new version env: OPENSSL_VER: ${{ matrix.openssl_ver }} diff --git a/Misc/NEWS.d/next/Build/2026-01-17-15-31-19.gh-issue-143960.Zi0EqR.rst b/Misc/NEWS.d/next/Build/2026-01-17-15-31-19.gh-issue-143960.Zi0EqR.rst new file mode 100644 index 00000000000..2b8e01f937d --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-01-17-15-31-19.gh-issue-143960.Zi0EqR.rst @@ -0,0 +1 @@ +Add support for OpenSSL 3.6, drop EOL 3.2. Patch by Hugo van Kemenade. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 7dd57e7892a..2bcf864e759 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -150,7 +150,7 @@ static void _PySSLFixErrno(void) { /* Include generated data (error codes) */ /* See Tools/ssl/make_ssl_data.py for notes on adding a new version. */ #if (OPENSSL_VERSION_NUMBER >= 0x30401000L) -#include "_ssl_data_35.h" +#include "_ssl_data_36.h" #elif (OPENSSL_VERSION_NUMBER >= 0x30100000L) #include "_ssl_data_340.h" #elif (OPENSSL_VERSION_NUMBER >= 0x30000000L) diff --git a/Modules/_ssl_data_35.h b/Modules/_ssl_data_36.h similarity index 99% rename from Modules/_ssl_data_35.h rename to Modules/_ssl_data_36.h index e4919b550e3..02b8b66e80f 100644 --- a/Modules/_ssl_data_35.h +++ b/Modules/_ssl_data_36.h @@ -1,6 +1,6 @@ /* File generated by Tools/ssl/make_ssl_data.py */ -/* Generated on 2025-10-04T17:49:19.148321+00:00 */ -/* Generated from Git commit openssl-3.5.4-0-gc1eeb9406 */ +/* Generated on 2026-01-17T13:03:49.335767+00:00 */ +/* Generated from Git commit openssl-3.6.0-0-g7b371d80d9 */ /* generated from args.lib2errnum */ static struct py_ssl_library_code library_codes[] = { @@ -1863,6 +1863,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"NOT_KEK", 46, 123}, #endif + #ifdef CMS_R_NOT_KEM + {"NOT_KEM", ERR_LIB_CMS, CMS_R_NOT_KEM}, + #else + {"NOT_KEM", 46, 197}, + #endif #ifdef CMS_R_NOT_KEY_AGREEMENT {"NOT_KEY_AGREEMENT", ERR_LIB_CMS, CMS_R_NOT_KEY_AGREEMENT}, #else @@ -2058,6 +2063,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNKNOWN_ID", 46, 150}, #endif + #ifdef CMS_R_UNKNOWN_KDF_ALGORITHM + {"UNKNOWN_KDF_ALGORITHM", ERR_LIB_CMS, CMS_R_UNKNOWN_KDF_ALGORITHM}, + #else + {"UNKNOWN_KDF_ALGORITHM", 46, 198}, + #endif #ifdef CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM {"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM}, #else @@ -2078,6 +2088,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"UNSUPPORTED_ENCRYPTION_TYPE", 46, 192}, #endif + #ifdef CMS_R_UNSUPPORTED_KDF_ALGORITHM + {"UNSUPPORTED_KDF_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KDF_ALGORITHM}, + #else + {"UNSUPPORTED_KDF_ALGORITHM", 46, 199}, + #endif #ifdef CMS_R_UNSUPPORTED_KEK_ALGORITHM {"UNSUPPORTED_KEK_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEK_ALGORITHM}, #else @@ -5763,6 +5778,11 @@ static struct py_ssl_error_code error_codes[] = { #else {"PSS_SALTLEN_TOO_SMALL", 57, 172}, #endif + #ifdef PROV_R_REPEATED_PARAMETER + {"REPEATED_PARAMETER", ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER}, + #else + {"REPEATED_PARAMETER", 57, 252}, + #endif #ifdef PROV_R_REQUEST_TOO_LARGE_FOR_DRBG {"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG}, #else diff --git a/Tools/ssl/make_ssl_data.py b/Tools/ssl/make_ssl_data.py index 286f0e5f54a..439dbaf882d 100755 --- a/Tools/ssl/make_ssl_data.py +++ b/Tools/ssl/make_ssl_data.py @@ -17,8 +17,8 @@ git tag --list 'openssl-*' git switch --detach openssl-3.4.1 -After generating the definitions, compare the result with newest pre-existing file. -You can use a command like: +After generating the definitions, compare the result with the newest +pre-existing file. You can use a command like: git diff --no-index Modules/_ssl_data_340.h Modules/_ssl_data_341.h diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 56976de4998..828fb8b44f9 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -45,14 +45,15 @@ OPENSSL_OLD_VERSIONS = [ "1.1.1w", "3.1.8", + "3.2.6", ] OPENSSL_RECENT_VERSIONS = [ "3.0.18", - "3.2.6", "3.3.5", "3.4.3", "3.5.4", + "3.6.0", # See make_ssl_data.py for notes on adding a new version. ] From 43bb6300b3e1b477436592ecbbbebbe1534499cf Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 20 Jan 2026 12:51:55 -0500 Subject: [PATCH 025/133] gh-143939: Fix assignment to `_PyThreadStateImpl.generator_return_kind` (gh-143951) The assignment to generator_return_kind has to be after any potentially escaping calls to ensure that it's not overwritten. --- Lib/test/test_coroutines.py | 14 ++++++++++++++ .../2026-01-16-23-19-38.gh-issue-143939.w9TWch.rst | 3 +++ Objects/genobject.c | 3 +++ Python/ceval.c | 4 +++- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-16-23-19-38.gh-issue-143939.w9TWch.rst diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 6ad7e7994f3..93e9e7a8393 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -2265,6 +2265,20 @@ def c(): # before fixing, visible stack from throw would be shorter than from send. self.assertEqual(len_send, len_throw) + def test_call_generator_in_frame_clear(self): + # gh-143939: Running a generator while clearing the coroutine's frame + # should not be misinterpreted as a yield. + class CallGeneratorOnDealloc: + def __del__(self): + next(x for x in [1]) + + async def coro(): + obj = CallGeneratorOnDealloc() + return 42 + + yielded, result = run_async(coro()) + self.assertEqual(yielded, []) + self.assertEqual(result, 42) @unittest.skipIf( support.is_emscripten or support.is_wasi, diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-16-23-19-38.gh-issue-143939.w9TWch.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-16-23-19-38.gh-issue-143939.w9TWch.rst new file mode 100644 index 00000000000..47423663e07 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-16-23-19-38.gh-issue-143939.w9TWch.rst @@ -0,0 +1,3 @@ +Fix erroneous "cannot reuse already awaited coroutine" error that could +occur when a generator was run during the process of clearing a coroutine's +frame. diff --git a/Objects/genobject.c b/Objects/genobject.c index 09407d60af6..fcdb9017a35 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -280,6 +280,9 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, int exc) if (return_kind == GENERATOR_YIELD) { assert(result != NULL && !_PyErr_Occurred(tstate)); +#ifndef Py_GIL_DISABLED + assert(FRAME_STATE_SUSPENDED(gen->gi_frame_state)); +#endif *presult = result; return PYGEN_NEXT; } diff --git a/Python/ceval.c b/Python/ceval.c index 87481ba6d03..bdf1e9bb742 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1914,7 +1914,6 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) assert(frame->owner == FRAME_OWNED_BY_GENERATOR); PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); 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; @@ -1922,6 +1921,9 @@ clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) frame->previous = NULL; _PyFrame_ClearExceptCode(frame); _PyErr_ClearExcState(&gen->gi_exc_state); + // gh-143939: There must not be any escaping calls between setting + // the generator return kind and returning from _PyEval_EvalFrame. + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_RETURN; } void From 48b6866047ab7d6001ff253053ee239ad2862277 Mon Sep 17 00:00:00 2001 From: Neil Schemenauer Date: Tue, 20 Jan 2026 10:01:09 -0800 Subject: [PATCH 026/133] gh-144054: no deferred refcount for untracked (gh-144081) This reverts gh-144055 and fixes the bug in a different way. Deferred reference counting relies on the object being tracked by the GC, otherwise the object will live until interpreter shutdown. So, take care that we do not enable deferred reference counting for objects that are untracked. Also, if a tuple has deferred reference counting enabled, don't untrack it. --- Python/gc_free_threading.c | 58 +++++++++++++++----------------------- Python/specialize.c | 2 +- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index beb3fa588f4..0ec9c58a792 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -308,18 +308,17 @@ disable_deferred_refcounting(PyObject *op) // should also be disabled when we turn off deferred refcounting. _PyObject_DisablePerThreadRefcounting(op); } - if (_PyObject_GC_IS_TRACKED(op)) { - // Generators and frame objects may contain deferred references to other - // objects. If the pointed-to objects are part of cyclic trash, we may - // have disabled deferred refcounting on them and need to ensure that we - // use strong references, in case the generator or frame object is - // resurrected by a finalizer. - if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) { - frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe); - } - else if (PyFrame_Check(op)) { - frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame); - } + + // Generators and frame objects may contain deferred references to other + // objects. If the pointed-to objects are part of cyclic trash, we may + // have disabled deferred refcounting on them and need to ensure that we + // use strong references, in case the generator or frame object is + // resurrected by a finalizer. + if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) { + frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe); + } + else if (PyFrame_Check(op)) { + frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame); } } @@ -507,6 +506,10 @@ gc_visit_thread_stacks(PyInterpreterState *interp, struct collection_state *stat static bool gc_maybe_untrack(PyObject *op) { + if (_PyObject_HasDeferredRefcount(op)) { + // deferred refcounting only works if the object is tracked + return false; + } // Currently we only check for tuples containing only non-GC objects. In // theory we could check other immutable objects that contain references // to non-GC objects. @@ -1019,7 +1022,7 @@ update_refs(const mi_heap_t *heap, const mi_heap_area_t *area, } _PyObject_ASSERT(op, refcount >= 0); - if (refcount > 0 && !_PyObject_HasDeferredRefcount(op)) { + if (refcount > 0) { if (gc_maybe_untrack(op)) { gc_restore_refs(op); return true; @@ -1241,30 +1244,19 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, return true; } + if (state->reason == _Py_GC_REASON_SHUTDOWN) { + // Disable deferred refcounting for reachable objects as well during + // interpreter shutdown. This ensures that these objects are collected + // immediately when their last reference is removed. + disable_deferred_refcounting(op); + } + // object is reachable, restore `ob_tid`; we're done with these objects gc_restore_tid(op); gc_clear_alive(op); return true; } -// Disable deferred refcounting for reachable objects during interpreter -// shutdown. This ensures that these objects are collected immediately when -// their last reference is removed. This needs to consider both tracked and -// untracked GC objects, since either might have deferred refcounts enabled. -static bool -scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area, - void *block, size_t block_size, void *args) -{ - PyObject *op = op_from_block_all_gc(block, args); - if (op == NULL) { - return true; - } - if (!_Py_IsImmortal(op)) { - disable_deferred_refcounting(op); - } - return true; -} - static int move_legacy_finalizer_reachable(struct collection_state *state); @@ -1499,10 +1491,6 @@ deduce_unreachable_heap(PyInterpreterState *interp, // Restores ob_tid for reachable objects. gc_visit_heaps(interp, &scan_heap_visitor, &state->base); - if (state->reason == _Py_GC_REASON_SHUTDOWN) { - gc_visit_heaps(interp, &scan_heap_disable_deferred, &state->base); - } - if (state->legacy_finalizers.head) { // There may be objects reachable from legacy finalizers that are in // the unreachable set. We need to mark them as reachable. diff --git a/Python/specialize.c b/Python/specialize.c index 432053f8522..845416a1d5b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -362,7 +362,7 @@ static uint32_t function_get_version(PyObject *o, int opcode); static void maybe_enable_deferred_ref_count(PyObject *op) { - if (!_Py_IsOwnedByCurrentThread(op)) { + if (!_Py_IsOwnedByCurrentThread(op) && _PyObject_GC_IS_TRACKED(op)) { // For module level variables that are heavily used from multiple // threads, deferred reference counting provides good scaling // benefits. The downside is that the object will only be deallocated From 27a7160b8b0c59634995787d83df5e7d698b66b6 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Wed, 21 Jan 2026 03:47:38 +0900 Subject: [PATCH 027/133] gh-141504: Move PYTHON_UOPS_OPTIMIZE to policy object (GH-144082) --- Include/internal/pycore_interp_structs.h | 1 + Python/optimizer.c | 6 +----- Python/pystate.c | 8 ++++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_interp_structs.h b/Include/internal/pycore_interp_structs.h index f11448b0669..723657e4cef 100644 --- a/Include/internal/pycore_interp_structs.h +++ b/Include/internal/pycore_interp_structs.h @@ -411,6 +411,7 @@ typedef struct _PyOptimizationConfig { // Optimization flags bool specialization_enabled; + bool uops_optimize_enabled; } _PyOptimizationConfig; struct diff --git a/Python/optimizer.c b/Python/optimizer.c index ab0ef3db4e4..15a1eb5a177 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1514,11 +1514,7 @@ uop_optimize( _PyBloomFilter *dependencies = &_tstate->jit_tracer_state->prev_state.dependencies; _PyUOpInstruction *buffer = _tstate->jit_tracer_state->code_buffer; OPT_STAT_INC(attempts); - char *env_var = Py_GETENV("PYTHON_UOPS_OPTIMIZE"); - bool is_noopt = true; - if (env_var == NULL || *env_var == '\0' || *env_var > '0') { - is_noopt = false; - } + bool is_noopt = !tstate->interp->opt_config.uops_optimize_enabled; int curr_stackentries = _tstate->jit_tracer_state->initial_state.stack_depth; int length = _tstate->jit_tracer_state->prev_state.code_curr_size; if (length <= CODE_SIZE_NO_PROGRESS) { diff --git a/Python/pystate.c b/Python/pystate.c index 86dee70734a..89374e16722 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -522,6 +522,13 @@ is_env_enabled(const char *env_name) return env && *env != '\0' && *env != '0'; } +static inline bool +is_env_disabled(const char *env_name) +{ + char *env = Py_GETENV(env_name); + return env != NULL && *env == '0'; +} + static inline void init_policy(uint16_t *target, const char *env_name, uint16_t default_value, long min_value, long max_value) @@ -619,6 +626,7 @@ init_interpreter(PyInterpreterState *interp, SIDE_EXIT_INITIAL_BACKOFF, 0, MAX_BACKOFF); interp->opt_config.specialization_enabled = !is_env_enabled("PYTHON_SPECIALIZATION_OFF"); + interp->opt_config.uops_optimize_enabled = !is_env_disabled("PYTHON_UOPS_OPTIMIZE"); if (interp != &runtime->_main_interpreter) { /* Fix the self-referential, statically initialized fields. */ interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp); From 6262704b134db2a4ba12e85ecfbd968534f28b45 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 20 Jan 2026 14:45:42 -0600 Subject: [PATCH 028/133] gh-143921: Reject control characters in IMAP commands --- Lib/imaplib.py | 4 +++- Lib/test/test_imaplib.py | 6 ++++++ .../Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 22a0afcd981..cb3edceae0d 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -129,7 +129,7 @@ # We compile these in _mode_xxx. _Literal = br'.*{(?P\d+)}$' _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' - +_control_chars = re.compile(b'[\x00-\x1F\x7F]') class IMAP4: @@ -1105,6 +1105,8 @@ def _command(self, name, *args): if arg is None: continue if isinstance(arg, str): arg = bytes(arg, self._encoding) + if _control_chars.search(arg): + raise ValueError("Control characters not allowed in commands") data = data + b' ' + arg literal = self.literal diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index 430fa71fa29..cb5454b40ec 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -657,6 +657,12 @@ def test_unselect(self): self.assertEqual(data[0], b'Returned to authenticated state. (Success)') self.assertEqual(client.state, 'AUTH') + def test_control_characters(self): + client, _ = self._setup(SimpleIMAPHandler) + for c0 in support.control_characters_c0(): + with self.assertRaises(ValueError): + client.login(f'user{c0}', 'pass') + # property tests def test_file_property_should_not_be_accessed(self): diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst new file mode 100644 index 00000000000..4e13fe92bc6 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst @@ -0,0 +1 @@ +Reject control characters in IMAP commands. From f25509e78e8be6ea73c811ac2b8c928c28841b9f Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 20 Jan 2026 14:45:58 -0600 Subject: [PATCH 029/133] gh-143925: Reject control characters in data: URL mediatypes --- Lib/test/test_urllib.py | 8 ++++++++ Lib/urllib/request.py | 5 +++++ .../2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst | 1 + 3 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index ae524c5ffba..2dd739b77b8 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -10,6 +10,7 @@ from test import support from test.support import os_helper from test.support import socket_helper +from test.support import control_characters_c0 import os import socket try: @@ -590,6 +591,13 @@ def test_invalid_base64_data(self): # missing padding character self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=') + def test_invalid_mediatype(self): + for c0 in control_characters_c0(): + self.assertRaises(ValueError,urllib.request.urlopen, + f'data:text/html;{c0},data') + for c0 in control_characters_c0(): + self.assertRaises(ValueError,urllib.request.urlopen, + f'data:text/html{c0};base64,ZGF0YQ==') class urlretrieve_FileTests(unittest.TestCase): """Test urllib.urlretrieve() on local files""" diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index f32de189b13..f5f17f223a4 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1636,6 +1636,11 @@ def data_open(self, req): scheme, data = url.split(":",1) mediatype, data = data.split(",",1) + # Disallow control characters within mediatype. + if re.search(r"[\x00-\x1F\x7F]", mediatype): + raise ValueError( + "Control characters not allowed in data: mediatype") + # even base64 encoded data URLs might be quoted so unquote in any case: data = unquote_to_bytes(data) if mediatype.endswith(";base64"): diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst new file mode 100644 index 00000000000..46109dfbef3 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst @@ -0,0 +1 @@ +Reject control characters in ``data:`` URL media types. From b234a2b67539f787e191d2ef19a7cbdce32874e7 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 20 Jan 2026 14:46:32 -0600 Subject: [PATCH 030/133] gh-143923: Reject control characters in POP3 commands --- Lib/poplib.py | 2 ++ Lib/test/test_poplib.py | 8 ++++++++ .../2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 + 3 files changed, 11 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst diff --git a/Lib/poplib.py b/Lib/poplib.py index 4469bff44b4..b97274c5c32 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -122,6 +122,8 @@ def _putline(self, line): def _putcmd(self, line): if self._debugging: print('*cmd*', repr(line)) line = bytes(line, self.encoding) + if re.search(b'[\x00-\x1F\x7F]', line): + raise ValueError('Control characters not allowed in commands') self._putline(line) diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py index ef2da97f867..18ca7cb5568 100644 --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -17,6 +17,7 @@ from test.support import threading_helper from test.support import asynchat from test.support import asyncore +from test.support import control_characters_c0 test_support.requires_working_socket(module=True) @@ -395,6 +396,13 @@ def test_quit(self): self.assertIsNone(self.client.sock) self.assertIsNone(self.client.file) + def test_control_characters(self): + for c0 in control_characters_c0(): + with self.assertRaises(ValueError): + self.client.user(f'user{c0}') + with self.assertRaises(ValueError): + self.client.pass_(f'{c0}pass') + @requires_ssl def test_stls_capa(self): capa = self.client.capa() diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst new file mode 100644 index 00000000000..3cde4df3e00 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst @@ -0,0 +1 @@ +Reject control characters in POP3 commands. From 95746b3a13a985787ef53b977129041971ed7f70 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Tue, 20 Jan 2026 15:23:42 -0600 Subject: [PATCH 031/133] gh-143919: Reject control characters in http cookies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartosz Sławecki Co-authored-by: sobolevn --- Doc/library/http.cookies.rst | 4 +- Lib/http/cookies.py | 25 +++++++-- Lib/test/test_http_cookies.py | 52 +++++++++++++++++-- ...-01-16-11-13-15.gh-issue-143919.kchwZV.rst | 1 + 4 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst index 88e978d7f5e..50b65459d2f 100644 --- a/Doc/library/http.cookies.rst +++ b/Doc/library/http.cookies.rst @@ -294,9 +294,9 @@ The following example demonstrates how to use the :mod:`http.cookies` module. Set-Cookie: chips=ahoy Set-Cookie: vienna=finger >>> C = cookies.SimpleCookie() - >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') + >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";') >>> print(C) - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;" >>> C = cookies.SimpleCookie() >>> C["oreo"] = "doublestuff" >>> C["oreo"]["path"] = "/" diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py index 74349bb63d6..917280037d4 100644 --- a/Lib/http/cookies.py +++ b/Lib/http/cookies.py @@ -87,9 +87,9 @@ such trickeries do not confuse it. >>> C = cookies.SimpleCookie() - >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') + >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";') >>> print(C) - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;" Each element of the Cookie also supports all of the RFC 2109 Cookie attributes. Here's an example which sets the Path @@ -170,6 +170,15 @@ class CookieError(Exception): }) _is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch +_control_character_re = re.compile(r'[\x00-\x1F\x7F]') + + +def _has_control_character(*val): + """Detects control characters within a value. + Supports any type, as header values can be any type. + """ + return any(_control_character_re.search(str(v)) for v in val) + def _quote(str): r"""Quote a string for use in a cookie header. @@ -294,12 +303,16 @@ def __setitem__(self, K, V): K = K.lower() if not K in self._reserved: raise CookieError("Invalid attribute %r" % (K,)) + if _has_control_character(K, V): + raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}") dict.__setitem__(self, K, V) def setdefault(self, key, val=None): key = key.lower() if key not in self._reserved: raise CookieError("Invalid attribute %r" % (key,)) + if _has_control_character(key, val): + raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,)) return dict.setdefault(self, key, val) def __eq__(self, morsel): @@ -335,6 +348,9 @@ def set(self, key, val, coded_val): raise CookieError('Attempt to set a reserved key %r' % (key,)) if not _is_legal_key(key): raise CookieError('Illegal key %r' % (key,)) + if _has_control_character(key, val, coded_val): + raise CookieError( + "Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,)) # It's a good key, so save it. self._key = key @@ -488,7 +504,10 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): result = [] items = sorted(self.items()) for key, value in items: - result.append(value.output(attrs, header)) + value_output = value.output(attrs, header) + if _has_control_character(value_output): + raise CookieError("Control characters are not allowed in cookies") + result.append(value_output) return sep.join(result) __str__ = output diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py index c2ed30831b2..7d072d5fd67 100644 --- a/Lib/test/test_http_cookies.py +++ b/Lib/test/test_http_cookies.py @@ -17,10 +17,10 @@ def test_basic(self): 'repr': "", 'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'}, - {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"', - 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'}, - 'repr': '''''', - 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'}, + {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=;"', + 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=;'}, + 'repr': '''''', + 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=;"'}, # Check illegal cookies that have an '=' char in an unquoted value {'data': 'keebler=E=mc2', @@ -594,6 +594,50 @@ def test_repr(self): r'Set-Cookie: key=coded_val; ' r'expires=\w+, \d+ \w+ \d+ \d+:\d+:\d+ \w+') + def test_control_characters(self): + for c0 in support.control_characters_c0(): + morsel = cookies.Morsel() + + # .__setitem__() + with self.assertRaises(cookies.CookieError): + morsel[c0] = "val" + with self.assertRaises(cookies.CookieError): + morsel["path"] = c0 + + # .setdefault() + with self.assertRaises(cookies.CookieError): + morsel.setdefault("path", c0) + with self.assertRaises(cookies.CookieError): + morsel.setdefault(c0, "val") + + # .set() + with self.assertRaises(cookies.CookieError): + morsel.set(c0, "val", "coded-value") + with self.assertRaises(cookies.CookieError): + morsel.set("path", c0, "coded-value") + with self.assertRaises(cookies.CookieError): + morsel.set("path", "val", c0) + + def test_control_characters_output(self): + # Tests that even if the internals of Morsel are modified + # that a call to .output() has control character safeguards. + for c0 in support.control_characters_c0(): + morsel = cookies.Morsel() + morsel.set("key", "value", "coded-value") + morsel._key = c0 # Override private variable. + cookie = cookies.SimpleCookie() + cookie["cookie"] = morsel + with self.assertRaises(cookies.CookieError): + cookie.output() + + morsel = cookies.Morsel() + morsel.set("key", "value", "coded-value") + morsel._coded_value = c0 # Override private variable. + cookie = cookies.SimpleCookie() + cookie["cookie"] = morsel + with self.assertRaises(cookies.CookieError): + cookie.output() + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(cookies)) diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst new file mode 100644 index 00000000000..788c3e4ac2e --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst @@ -0,0 +1 @@ +Reject control characters in :class:`http.cookies.Morsel` fields and values. From 48795b6460e16dff72add0675a7bf8e1f029108e Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Tue, 20 Jan 2026 19:28:48 -0600 Subject: [PATCH 032/133] GH-143948: Explain graphlib's cycle-finding code (#143950) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explain topsort's cycle-finding algorithm, and why it's written that way. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/graphlib.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/Lib/graphlib.py b/Lib/graphlib.py index 7961c9c5cac..af5245ccbcd 100644 --- a/Lib/graphlib.py +++ b/Lib/graphlib.py @@ -199,6 +199,7 @@ def done(self, *nodes): self._ready_nodes.append(successor) self._nfinished += 1 + # See note "On Finding Cycles" at the bottom. def _find_cycle(self): n2i = self._node2info stack = [] @@ -212,8 +213,6 @@ def _find_cycle(self): while True: if node in seen: - # If we have seen already the node and is in the - # current stack we have found a cycle. if node in node2stacki: return stack[node2stacki[node] :] + [node] # else go on to get next successor @@ -228,11 +227,15 @@ def _find_cycle(self): while stack: try: node = itstack[-1]() - break + break # resume at top of "while True:" except StopIteration: + # no more successors; pop the stack + # and continue looking up del node2stacki[stack.pop()] itstack.pop() else: + # stack is empty; look for a fresh node to + # start over from (a node not yet in seen) break return None @@ -252,3 +255,55 @@ def static_order(self): self.done(*node_group) __class_getitem__ = classmethod(GenericAlias) + + +# On Finding Cycles +# ----------------- +# There is a (at least one) total order if and only if the graph is +# acyclic. +# +# When it is cyclic, "there's a cycle - somewhere!" isn't very helpful. +# In theory, it would be most helpful to partition the graph into +# strongly connected components (SCCs) and display those with more than +# one node. Then all cycles could easily be identified "by eyeball". +# +# That's a lot of work, though, and we can get most of the benefit much +# more easily just by showing a single specific cycle. +# +# Approaches to that are based on breadth first or depth first search +# (BFS or DFS). BFS is most natural, which can easily be arranged to +# find a shortest-possible cycle. But memory burden can be high, because +# every path-in-progress has to keep its own idea of what "the path" is +# so far. +# +# DFS is much easier on RAM, only requiring keeping track of _the_ path +# from the starting node to the current node at the current recursion +# level. But there may be any number of nodes, and so there's no bound +# on recursion depth short of the total number of nodes. +# +# So we use an iterative version of DFS, keeping an exploit list +# (`stack`) of the path so far. A parallel stack (`itstack`) holds the +# `__next__` method of an iterator over the current level's node's +# successors, so when backtracking to a shallower level we can just call +# that to get the node's next successor. This is state that a recursive +# version would implicitly store in a `for` loop's internals. +# +# `seen()` is a set recording which nodes have already been, at some +# time, pushed on the stack. If a node has been pushed on the stack, DFS +# will find any cycle it's part of, so there's no need to ever look at +# it again. +# +# Finally, `node2stacki` maps a node to its index on the current stack, +# for and only for nodes currently _on_ the stack. If a successor to be +# pushed on the stack is in that dict, the node is already on the path, +# at that index. The cycle is then `stack[that_index :] + [node]`. +# +# As is often the case when removing recursion, the control flow looks a +# bit off. The "while True:" loop here rarely actually loops - it's only +# looking to go "up the stack" until finding a level that has another +# successor to consider, emulating a chain of returns in a recursive +# version. +# +# Worst cases: O(V+E) for time, and O(V) for memory, where V is the +# number of nodes and E the number of edges (which may be quadratic in +# V!). It requires care to ensure these bounds are met. From 9060b4abbe475591b6230b23c2afefeff26fcca5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 21 Jan 2026 09:41:58 +0200 Subject: [PATCH 033/133] gh-125346: Deprecate accepting standard Base64 alphabet when alternative alphabet is used (GH-141128) Emit a warning in base64.urlsafe_b64decode() and base64.b64decode() when the "+" or "/" characters occur in the Base64 data with alternative alphabet if they are not the part of the alternative alphabet. It is a DeprecationWarning in the strict mode (will be error) and a FutureWarning in non-strict mode (will be ignored). --- Doc/library/base64.rst | 18 ++++++--- Doc/whatsnew/3.15.rst | 9 +++++ Lib/base64.py | 40 ++++++++++++++++--- Lib/test/test_base64.py | 31 ++++++++++---- ...-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst | 5 +++ 5 files changed, 86 insertions(+), 17 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 4876117f640..3e7884debd5 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -84,15 +84,20 @@ POST request. A :exc:`binascii.Error` exception is raised if *s* is incorrectly padded. - If *validate* is ``False`` (the default), characters that are neither + If *validate* is false (the default), characters that are neither in the normal base-64 alphabet nor the alternative alphabet are - discarded prior to the padding check. If *validate* is ``True``, - these non-alphabet characters in the input result in a - :exc:`binascii.Error`. + discarded prior to the padding check, but the ``+`` and ``/`` characters + keep their meaning if they are not in *altchars* (they will be discarded + in future Python versions). + If *validate* is true, these non-alphabet characters in the input + result in a :exc:`binascii.Error`. For more information about the strict base64 check, see :func:`binascii.a2b_base64` - May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2. + .. deprecated:: next + Accepting the ``+`` and ``/`` characters with an alternative alphabet + is now deprecated. + .. function:: standard_b64encode(s) @@ -123,6 +128,9 @@ POST request. ``/`` in the standard Base64 alphabet, and return the decoded :class:`bytes`. + .. deprecated:: next + Accepting the ``+`` and ``/`` characters is now deprecated. + .. function:: b32encode(s) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 1dd66065b0f..1d4961d7293 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1149,6 +1149,15 @@ Deprecated New deprecations ---------------- +* :mod:`base64`: + + * Accepting the ``+`` and ``/`` characters with an alternative alphabet in + :func:`~base64.b64decode` and :func:`~base64.urlsafe_b64decode` is now + deprecated. + In future Python versions they will be errors in the strict mode and + discarded in the non-strict mode. + (Contributed by Serhiy Storchaka in :gh:`125346`.) + * CLI: * Deprecate :option:`-b` and :option:`!-bb` command-line options diff --git a/Lib/base64.py b/Lib/base64.py index e62ae6aff58..6e0da16b23c 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -72,20 +72,39 @@ def b64decode(s, altchars=None, validate=False): The result is returned as a bytes object. A binascii.Error is raised if s is incorrectly padded. - If validate is False (the default), characters that are neither in the + If validate is false (the default), characters that are neither in the normal base-64 alphabet nor the alternative alphabet are discarded prior - to the padding check. If validate is True, these non-alphabet characters + to the padding check. If validate is true, these non-alphabet characters in the input result in a binascii.Error. For more information about the strict base64 check, see: https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64 """ s = _bytes_from_decode_data(s) + badchar = None if altchars is not None: altchars = _bytes_from_decode_data(altchars) - assert len(altchars) == 2, repr(altchars) + if len(altchars) != 2: + raise ValueError(f'invalid altchars: {altchars!r}') + for b in b'+/': + if b not in altchars and b in s: + badchar = b + break s = s.translate(bytes.maketrans(altchars, b'+/')) - return binascii.a2b_base64(s, strict_mode=validate) + result = binascii.a2b_base64(s, strict_mode=validate) + if badchar is not None: + import warnings + if validate: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=True ' + f'will be an error in future Python versions', + DeprecationWarning, stacklevel=2) + else: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=False ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) + return result def standard_b64encode(s): @@ -130,8 +149,19 @@ def urlsafe_b64decode(s): The alphabet uses '-' instead of '+' and '_' instead of '/'. """ s = _bytes_from_decode_data(s) + badchar = None + for b in b'+/': + if b in s: + badchar = b + break s = s.translate(_urlsafe_decode_translation) - return b64decode(s) + result = binascii.a2b_base64(s, strict_mode=False) + if badchar is not None: + import warnings + warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) + return result diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index 120c5824a42..d02992903f1 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -292,6 +292,11 @@ def test_b64decode_altchars(self): eq(base64.b64decode(data, altchars=altchars_str), res) eq(base64.b64decode(data_str, altchars=altchars_str), res) + self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+') + self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-') + self.assertRaises(ValueError, base64.b64decode, '', altchars='+') + self.assertRaises(ValueError, base64.b64decode, '', altchars='+/-') + def test_b64decode_padding_error(self): self.assertRaises(binascii.Error, base64.b64decode, b'abc') self.assertRaises(binascii.Error, base64.b64decode, 'abc') @@ -323,13 +328,25 @@ def test_b64decode_invalid_chars(self): with self.assertRaises(binascii.Error): base64.b64decode(bstr.decode('ascii'), validate=True) - # Normal alphabet characters not discarded when alternative given - res = b'\xfb\xef\xff' - self.assertEqual(base64.b64decode(b'++//', validate=True), res) - self.assertEqual(base64.b64decode(b'++//', '-_', validate=True), res) - self.assertEqual(base64.b64decode(b'--__', '-_', validate=True), res) - self.assertEqual(base64.urlsafe_b64decode(b'++//'), res) - self.assertEqual(base64.urlsafe_b64decode(b'--__'), res) + # Normal alphabet characters will be discarded when alternative given + with self.assertWarns(FutureWarning): + self.assertEqual(base64.b64decode(b'++++', altchars=b'-_'), + b'\xfb\xef\xbe') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.b64decode(b'////', altchars=b'-_'), + b'\xff\xff\xff') + with self.assertWarns(DeprecationWarning): + self.assertEqual(base64.b64decode(b'++++', altchars=b'-_', validate=True), + b'\xfb\xef\xbe') + with self.assertWarns(DeprecationWarning): + self.assertEqual(base64.b64decode(b'////', altchars=b'-_', validate=True), + b'\xff\xff\xff') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff') + with self.assertRaises(binascii.Error): + base64.b64decode(b'+/!', altchars=b'-_') def _altchars_strategy(): """Generate 'altchars' for base64 encoding.""" diff --git a/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst b/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst new file mode 100644 index 00000000000..187a6ebbe79 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst @@ -0,0 +1,5 @@ +Accepting ``+`` and ``/`` characters with an alternative alphabet in +:func:`base64.b64decode` and :func:`base64.urlsafe_b64decode` is now +deprecated. +In future Python versions they will be errors in the strict mode and +discarded in the non-strict mode. From 4ef30a5871db2043712945e64f33af81938d68dc Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Wed, 21 Jan 2026 18:33:56 +0800 Subject: [PATCH 034/133] gh-144085: Add `{gi,cr}_suspended` to `inspect` comments and `generator/coroutine` tests (#144086) --- Lib/inspect.py | 1 + Lib/test/test_types.py | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Lib/inspect.py b/Lib/inspect.py index 07c4e28f0d9..0dba3c6628c 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -348,6 +348,7 @@ def isgenerator(object): gi_frame frame object or possibly None once the generator has been exhausted gi_running set to 1 when generator is executing, 0 otherwise + gi_suspended set to 1 when the generator is suspended at a yield point, 0 otherwise gi_yieldfrom object being iterated by yield from or None __iter__() defined to support iteration over container diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 4595e7e5d3e..b0d2348c0e1 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2294,8 +2294,8 @@ def foo(): return gen self.assertIs(wrapper.__name__, gen.__name__) # Test AttributeErrors - for name in {'gi_running', 'gi_frame', 'gi_code', 'gi_yieldfrom', - 'cr_running', 'cr_frame', 'cr_code', 'cr_await'}: + for name in {'gi_running', 'gi_frame', 'gi_code', 'gi_yieldfrom', 'gi_suspended', + 'cr_running', 'cr_frame', 'cr_code', 'cr_await', 'cr_suspended'}: with self.assertRaises(AttributeError): getattr(wrapper, name) @@ -2304,14 +2304,17 @@ def foo(): return gen gen.gi_frame = object() gen.gi_code = object() gen.gi_yieldfrom = object() + gen.gi_suspended = object() self.assertIs(wrapper.gi_running, gen.gi_running) self.assertIs(wrapper.gi_frame, gen.gi_frame) self.assertIs(wrapper.gi_code, gen.gi_code) self.assertIs(wrapper.gi_yieldfrom, gen.gi_yieldfrom) + self.assertIs(wrapper.gi_suspended, gen.gi_suspended) self.assertIs(wrapper.cr_running, gen.gi_running) self.assertIs(wrapper.cr_frame, gen.gi_frame) self.assertIs(wrapper.cr_code, gen.gi_code) self.assertIs(wrapper.cr_await, gen.gi_yieldfrom) + self.assertIs(wrapper.cr_suspended, gen.gi_suspended) wrapper.close() gen.close.assert_called_once_with() @@ -2430,7 +2433,7 @@ def foo(): return gen self.assertIs(wrapper.__await__(), gen) for name in ('__name__', '__qualname__', 'gi_code', - 'gi_running', 'gi_frame'): + 'gi_running', 'gi_frame', 'gi_suspended'): self.assertIs(getattr(foo(), name), getattr(gen, name)) self.assertIs(foo().cr_code, gen.gi_code) @@ -2493,8 +2496,8 @@ def coro(): self.assertEqual(repr(wrapper), str(wrapper)) self.assertTrue(set(dir(wrapper)).issuperset({ '__await__', '__iter__', '__next__', 'cr_code', 'cr_running', - 'cr_frame', 'gi_code', 'gi_frame', 'gi_running', 'send', - 'close', 'throw'})) + 'cr_frame', 'cr_suspended', 'gi_code', 'gi_frame', 'gi_running', + 'gi_suspended', 'send', 'close', 'throw'})) class FunctionTests(unittest.TestCase): From 4c7ec78092ece6de3e58d88f2b9d1557f7d30249 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Wed, 21 Jan 2026 16:47:14 +0300 Subject: [PATCH 035/133] gh-143869: Add PEP 757 functions to the limited API (#143906) Co-authored-by: Petr Viktorin --- Doc/c-api/long.rst | 12 +++--- Doc/data/stable_abi.dat | 9 +++++ Include/cpython/longintrepr.h | 39 ------------------- Include/longobject.h | 38 ++++++++++++++++++ Lib/test/test_stable_abi_ctypes.py | 6 +++ ...-01-16-15-04-26.gh-issue-143869.vf94km.rst | 5 +++ Misc/stable_abi.toml | 28 +++++++++++++ PC/python3dll.c | 6 +++ 8 files changed, 98 insertions(+), 45 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index ed9b37dc172..790ec8da109 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -687,7 +687,7 @@ Export API .. versionadded:: 3.14 -.. c:struct:: PyLongLayout +.. c:type:: PyLongLayout Layout of an array of "digits" ("limbs" in the GMP terminology), used to represent absolute value for arbitrary precision integers. @@ -727,7 +727,7 @@ Export API Get the native layout of Python :class:`int` objects. - See the :c:struct:`PyLongLayout` structure. + See the :c:type:`PyLongLayout` structure. The function must not be called before Python initialization nor after Python finalization. The returned layout is valid until Python is @@ -735,7 +735,7 @@ Export API in a process, and so it can be cached. -.. c:struct:: PyLongExport +.. c:type:: PyLongExport Export of a Python :class:`int` object. @@ -769,7 +769,7 @@ Export API Export a Python :class:`int` object. - *export_long* must point to a :c:struct:`PyLongExport` structure allocated + *export_long* must point to a :c:type:`PyLongExport` structure allocated by the caller. It must not be ``NULL``. On success, fill in *\*export_long* and return ``0``. @@ -799,7 +799,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer. .. versionadded:: 3.14 -.. c:struct:: PyLongWriter +.. c:type:: PyLongWriter A Python :class:`int` writer instance. @@ -827,7 +827,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer. The layout of *digits* is described by :c:func:`PyLong_GetNativeLayout`. Digits must be in the range [``0``; ``(1 << bits_per_digit) - 1``] - (where the :c:struct:`~PyLongLayout.bits_per_digit` is the number of bits + (where the :c:type:`~PyLongLayout.bits_per_digit` is the number of bits per digit). Any unused most significant digits must be set to ``0``. diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 9c5fdcefaf8..510e683c87e 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -389,8 +389,14 @@ func,PyList_SetSlice,3.2,, func,PyList_Size,3.2,, func,PyList_Sort,3.2,, data,PyList_Type,3.2,, +type,PyLongExport,3.15,,full-abi +type,PyLongLayout,3.15,,full-abi type,PyLongObject,3.2,,opaque data,PyLongRangeIter_Type,3.2,, +type,PyLongWriter,3.15,,opaque +func,PyLongWriter_Create,3.15,, +func,PyLongWriter_Discard,3.15,, +func,PyLongWriter_Finish,3.15,, func,PyLong_AsDouble,3.2,, func,PyLong_AsInt,3.13,, func,PyLong_AsInt32,3.14,, @@ -409,6 +415,8 @@ func,PyLong_AsUnsignedLongLong,3.2,, func,PyLong_AsUnsignedLongLongMask,3.2,, func,PyLong_AsUnsignedLongMask,3.2,, func,PyLong_AsVoidPtr,3.2,, +func,PyLong_Export,3.15,, +func,PyLong_FreeExport,3.15,, func,PyLong_FromDouble,3.2,, func,PyLong_FromInt32,3.14,, func,PyLong_FromInt64,3.14,, @@ -425,6 +433,7 @@ func,PyLong_FromUnsignedLongLong,3.2,, func,PyLong_FromUnsignedNativeBytes,3.14,, func,PyLong_FromVoidPtr,3.2,, func,PyLong_GetInfo,3.2,, +func,PyLong_GetNativeLayout,3.15,, data,PyLong_Type,3.2,, macro,PyMODEXPORT_FUNC,3.15,, data,PyMap_Type,3.2,, diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 4b6f97a5e47..804c1e9427e 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -138,45 +138,6 @@ _PyLong_CompactValue(const PyLongObject *op) #define PyUnstable_Long_CompactValue _PyLong_CompactValue - -/* --- Import/Export API -------------------------------------------------- */ - -typedef struct PyLongLayout { - uint8_t bits_per_digit; - uint8_t digit_size; - int8_t digits_order; - int8_t digit_endianness; -} PyLongLayout; - -PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void); - -typedef struct PyLongExport { - int64_t value; - uint8_t negative; - Py_ssize_t ndigits; - const void *digits; - // Member used internally, must not be used for other purpose. - Py_uintptr_t _reserved; -} PyLongExport; - -PyAPI_FUNC(int) PyLong_Export( - PyObject *obj, - PyLongExport *export_long); -PyAPI_FUNC(void) PyLong_FreeExport( - PyLongExport *export_long); - - -/* --- PyLongWriter API --------------------------------------------------- */ - -typedef struct PyLongWriter PyLongWriter; - -PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create( - int negative, - Py_ssize_t ndigits, - void **digits); -PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer); -PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer); - #ifdef __cplusplus } #endif diff --git a/Include/longobject.h b/Include/longobject.h index 19f06977036..38673bc1878 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -166,6 +166,44 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); +/* --- Import/Export API -------------------------------------------------- */ + +typedef struct PyLongLayout { + uint8_t bits_per_digit; + uint8_t digit_size; + int8_t digits_order; + int8_t digit_endianness; +} PyLongLayout; + +PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void); + +typedef struct PyLongExport { + int64_t value; + uint8_t negative; + Py_ssize_t ndigits; + const void *digits; + // Member used internally, must not be used for other purpose. + Py_uintptr_t _reserved; +} PyLongExport; + +PyAPI_FUNC(int) PyLong_Export( + PyObject *obj, + PyLongExport *export_long); +PyAPI_FUNC(void) PyLong_FreeExport( + PyLongExport *export_long); + + +/* --- PyLongWriter API --------------------------------------------------- */ + +typedef struct PyLongWriter PyLongWriter; + +PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create( + int negative, + Py_ssize_t ndigits, + void **digits); +PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer); +PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer); + #ifndef Py_LIMITED_API # define Py_CPYTHON_LONGOBJECT_H # include "cpython/longobject.h" diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 2e93ac08f82..28f5dd11130 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -391,6 +391,9 @@ SYMBOL_NAMES = ( "PyList_Sort", "PyList_Type", "PyLongRangeIter_Type", + "PyLongWriter_Create", + "PyLongWriter_Discard", + "PyLongWriter_Finish", "PyLong_AsDouble", "PyLong_AsInt", "PyLong_AsInt32", @@ -409,6 +412,8 @@ SYMBOL_NAMES = ( "PyLong_AsUnsignedLongLongMask", "PyLong_AsUnsignedLongMask", "PyLong_AsVoidPtr", + "PyLong_Export", + "PyLong_FreeExport", "PyLong_FromDouble", "PyLong_FromInt32", "PyLong_FromInt64", @@ -425,6 +430,7 @@ SYMBOL_NAMES = ( "PyLong_FromUnsignedNativeBytes", "PyLong_FromVoidPtr", "PyLong_GetInfo", + "PyLong_GetNativeLayout", "PyLong_Type", "PyMap_Type", "PyMapping_Check", diff --git a/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst b/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst new file mode 100644 index 00000000000..60b0c1ec130 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst @@ -0,0 +1,5 @@ +Added :c:func:`PyLong_GetNativeLayout`, :c:struct:`PyLongLayout`, +:c:struct:`PyLongExport`, :c:func:`PyLong_Export`, +:c:func:`PyLong_FreeExport`, :c:struct:`PyLongWriter`, +:c:func:`PyLongWriter_Create`, :c:func:`PyLongWriter_Finish` and +:c:func:`PyLongWriter_Discard` to the limited API. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 31d22e64b84..63fd83868b6 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -41,6 +41,8 @@ # - 'full-abi': All of the struct is part of the ABI, including the size # (users may define arrays of these structs). # Typically used for initialization, rather than at runtime. +# Any members whose names start with an underscore are not part of the +# limited API; they're for CPython's use only. # - 'opaque': No members are part of the ABI, nor is the size. The Limited # API only handles these via pointers. The C definition should be # incomplete (opaque). @@ -2664,3 +2666,29 @@ [function.Py_SET_SIZE] # Before 3.15, this was a macro that accessed the PyObject member added = '3.15' + +# PEP 757 import/export API. + +[function.PyLong_GetNativeLayout] + added = '3.15' +[function.PyLong_Export] + added = '3.15' +[function.PyLong_FreeExport] + added = '3.15' +[function.PyLongWriter_Create] + added = '3.15' +[function.PyLongWriter_Finish] + added = '3.15' +[function.PyLongWriter_Discard] + added = '3.15' +[struct.PyLongWriter] + added = '3.15' + struct_abi_kind = 'opaque' +[struct.PyLongLayout] + added = '3.15' + struct_abi_kind = 'full-abi' +[struct.PyLongExport] + added = '3.15' + # Note: The `_reserved` member of this struct is for interal use only. + # (The definition of 'full-abi' was clarified when this entry was added.) + struct_abi_kind = 'full-abi' diff --git a/PC/python3dll.c b/PC/python3dll.c index 0d9e7e9a1ba..b23bc2b8f43 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -366,6 +366,8 @@ EXPORT_FUNC(PyLong_AsUnsignedLongLong) EXPORT_FUNC(PyLong_AsUnsignedLongLongMask) EXPORT_FUNC(PyLong_AsUnsignedLongMask) EXPORT_FUNC(PyLong_AsVoidPtr) +EXPORT_FUNC(PyLong_Export) +EXPORT_FUNC(PyLong_FreeExport) EXPORT_FUNC(PyLong_FromDouble) EXPORT_FUNC(PyLong_FromInt32) EXPORT_FUNC(PyLong_FromInt64) @@ -382,6 +384,10 @@ EXPORT_FUNC(PyLong_FromUnsignedLongLong) EXPORT_FUNC(PyLong_FromUnsignedNativeBytes) EXPORT_FUNC(PyLong_FromVoidPtr) EXPORT_FUNC(PyLong_GetInfo) +EXPORT_FUNC(PyLong_GetNativeLayout) +EXPORT_FUNC(PyLongWriter_Create) +EXPORT_FUNC(PyLongWriter_Discard) +EXPORT_FUNC(PyLongWriter_Finish) EXPORT_FUNC(PyMapping_Check) EXPORT_FUNC(PyMapping_GetItemString) EXPORT_FUNC(PyMapping_GetOptionalItem) From 5db331a561059afe7f7fedd75b4bc67550c988cd Mon Sep 17 00:00:00 2001 From: CF Bolz-Tereick Date: Wed, 21 Jan 2026 15:19:19 +0100 Subject: [PATCH 036/133] gh-144030: Add check that argument is callable to Python version of functools.lru_cache (#144031) Co-authored-by: sobolevn Co-authored-by: AN Long --- Lib/functools.py | 3 +++ Lib/test/test_functools.py | 7 +++++++ .../Library/2026-01-19-12-48-59.gh-issue-144030.7OK_gB.rst | 3 +++ 3 files changed, 13 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-19-12-48-59.gh-issue-144030.7OK_gB.rst diff --git a/Lib/functools.py b/Lib/functools.py index 075418b1605..59fc2a8fbf6 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -602,6 +602,9 @@ def decorating_function(user_function): return decorating_function def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo): + if not callable(user_function): + raise TypeError("the first argument must be callable") + # Constants shared by all lru cache instances: sentinel = object() # unique object used to signal cache misses make_key = _make_key # build a key from the function arguments diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 94b46939713..3801a82a610 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -2157,6 +2157,13 @@ def fib(n): with self.assertRaises(RecursionError): fib(support.exceeds_recursion_limit()) + def test_lru_checks_arg_is_callable(self): + with self.assertRaisesRegex( + TypeError, + "the first argument must be callable", + ): + self.module.lru_cache(1)('hello') + @py_functools.lru_cache() def py_cached_func(x, y): diff --git a/Misc/NEWS.d/next/Library/2026-01-19-12-48-59.gh-issue-144030.7OK_gB.rst b/Misc/NEWS.d/next/Library/2026-01-19-12-48-59.gh-issue-144030.7OK_gB.rst new file mode 100644 index 00000000000..ef3c0292540 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-19-12-48-59.gh-issue-144030.7OK_gB.rst @@ -0,0 +1,3 @@ +The Python implementation of :func:`functools.lru_cache` differed from the +default C implementation in that it did not check that its argument is +callable. This discrepancy is now fixed and both raise a :exc:`TypeError`. From f52af86cba644b6eeb32506a8948b6bf53a4f363 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 21 Jan 2026 15:33:05 +0000 Subject: [PATCH 037/133] Update install manager docs (python/pymanager#227) (GH-144079) --- Doc/using/windows.rst | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index a4bc336cc92..d286788e805 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -126,9 +126,8 @@ is also an unambiguous ``pymanager`` command. Scripted installs that are intending to use Python install manager should consider using ``pymanager``, due to the lower chance of encountering a conflict with existing installs. The only difference between the two commands is when running without any arguments: -``py`` will install and launch your default interpreter, while ``pymanager`` -will display help (``pymanager exec ...`` provides equivalent behaviour to -``py ...``). +``py`` will launch your default interpreter, while ``pymanager`` will display +help (``pymanager exec ...`` provides equivalent behaviour to ``py ...``). Each of these commands also has a windowed version that avoids creating a console window. These are ``pyw``, ``pythonw`` and ``pymanagerw``. A ``python3`` @@ -187,12 +186,11 @@ that virtual environment. In this scenario, the ``python`` command was likely already overridden and none of these checks occurred. However, this behaviour ensures that the ``py`` command can be used interchangeably. -When you launch either ``python`` or ``py`` but do not have any runtimes -installed, and the requested version is the default, it will be installed -automatically and then launched. Otherwise, the requested version will be -installed if automatic installation is configured (most likely by setting -``PYTHON_MANAGER_AUTOMATIC_INSTALL`` to ``true``), or if the ``py exec`` or -``pymanager exec`` forms of the command were used. +When no runtimes are installed, any launch command will try to install the +requested version and launch it. However, after any version is installed, only +the ``py exec ...`` and ``pymanager exec ...`` commands will install if the +requested version is absent. Other forms of commands will display an error and +direct you to use ``py install`` first. Command help @@ -301,6 +299,14 @@ To launch the runtime, directly execute the main executable (typically $> py install ... [-t=|--target=] +The ``py exec`` command will install the requested runtime if it is not already +present. This is controlled by the ``automatic_install`` configuration +(:envvar:`PYTHON_MANAGER_AUTOMATIC_INSTALL`), and is enabled by default. +If no runtimes are available at all, all launch commands will do an automatic +install if the configuration setting allows. This is to ensure a good experience +for new users, but should not generally be relied on rather than using the +``py exec`` command or explicit install commands. + .. _pymanager-offline: @@ -426,9 +432,11 @@ customization. By default, :file:`%TEMP%`. * - ``automatic_install`` - - ``PYTHON_MANAGER_AUTOMATIC_INSTALL`` - - True to allow automatic installs when using ``py exec`` to launch. - Other commands will not automatically install. + - .. envvar:: PYTHON_MANAGER_AUTOMATIC_INSTALL + - True to allow automatic installs when using ``py exec`` to launch (or + ``py`` when no runtimes are installed yet). + Other commands will not automatically install, regardless of this + setting. By default, true. * - ``include_unmanaged`` @@ -777,7 +785,7 @@ Troubleshooting If your Python install manager does not seem to be working correctly, please work through these tests and fixes to see if it helps. If not, please report an -issue at `our bug tracker `_, +issue at `our bug tracker `_, including any relevant log files (written to your :file:`%TEMP%` directory by default). From 9eab67d507cf655c877a7450f530c9f3fb8ff1f3 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 21 Jan 2026 15:58:27 +0000 Subject: [PATCH 038/133] GH-138245: Perform boolean guards by testing a single bit, rather than a full pointer comparison. (GH-143810) --- Include/internal/pycore_uop_ids.h | 2044 ++++++++++++------------ Include/internal/pycore_uop_metadata.h | 212 +++ Lib/test/test_capi/test_opt.py | 59 +- Python/bytecodes.c | 22 + Python/executor_cases.c.h | 1072 +++++++++++++ Python/optimizer_analysis.c | 28 + Python/optimizer_bytecodes.c | 36 +- Python/optimizer_cases.c.h | 32 + 8 files changed, 2478 insertions(+), 1027 deletions(-) diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 8fd7cef3368..5cda407ba89 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -131,62 +131,72 @@ extern "C" { #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER #define _GUARD_BINARY_OP_EXTEND 387 #define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS 388 -#define _GUARD_CALLABLE_ISINSTANCE 389 -#define _GUARD_CALLABLE_LEN 390 -#define _GUARD_CALLABLE_LIST_APPEND 391 -#define _GUARD_CALLABLE_STR_1 392 -#define _GUARD_CALLABLE_TUPLE_1 393 -#define _GUARD_CALLABLE_TYPE_1 394 -#define _GUARD_DORV_NO_DICT 395 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 396 -#define _GUARD_GLOBALS_VERSION 397 -#define _GUARD_IP_RETURN_GENERATOR 398 -#define _GUARD_IP_RETURN_VALUE 399 -#define _GUARD_IP_YIELD_VALUE 400 -#define _GUARD_IP__PUSH_FRAME 401 -#define _GUARD_IS_FALSE_POP 402 -#define _GUARD_IS_NONE_POP 403 -#define _GUARD_IS_NOT_NONE_POP 404 -#define _GUARD_IS_TRUE_POP 405 -#define _GUARD_KEYS_VERSION 406 -#define _GUARD_NOS_COMPACT_ASCII 407 -#define _GUARD_NOS_DICT 408 -#define _GUARD_NOS_FLOAT 409 -#define _GUARD_NOS_INT 410 -#define _GUARD_NOS_LIST 411 -#define _GUARD_NOS_NOT_NULL 412 -#define _GUARD_NOS_NULL 413 -#define _GUARD_NOS_OVERFLOWED 414 -#define _GUARD_NOS_TUPLE 415 -#define _GUARD_NOS_UNICODE 416 -#define _GUARD_NOT_EXHAUSTED_LIST 417 -#define _GUARD_NOT_EXHAUSTED_RANGE 418 -#define _GUARD_NOT_EXHAUSTED_TUPLE 419 -#define _GUARD_THIRD_NULL 420 -#define _GUARD_TOS_ANY_SET 421 -#define _GUARD_TOS_DICT 422 -#define _GUARD_TOS_FLOAT 423 -#define _GUARD_TOS_INT 424 -#define _GUARD_TOS_LIST 425 -#define _GUARD_TOS_OVERFLOWED 426 -#define _GUARD_TOS_SLICE 427 -#define _GUARD_TOS_TUPLE 428 -#define _GUARD_TOS_UNICODE 429 -#define _GUARD_TYPE_VERSION 430 -#define _GUARD_TYPE_VERSION_AND_LOCK 431 -#define _HANDLE_PENDING_AND_DEOPT 432 +#define _GUARD_BIT_IS_SET_POP 389 +#define _GUARD_BIT_IS_SET_POP_4 390 +#define _GUARD_BIT_IS_SET_POP_5 391 +#define _GUARD_BIT_IS_SET_POP_6 392 +#define _GUARD_BIT_IS_SET_POP_7 393 +#define _GUARD_BIT_IS_UNSET_POP 394 +#define _GUARD_BIT_IS_UNSET_POP_4 395 +#define _GUARD_BIT_IS_UNSET_POP_5 396 +#define _GUARD_BIT_IS_UNSET_POP_6 397 +#define _GUARD_BIT_IS_UNSET_POP_7 398 +#define _GUARD_CALLABLE_ISINSTANCE 399 +#define _GUARD_CALLABLE_LEN 400 +#define _GUARD_CALLABLE_LIST_APPEND 401 +#define _GUARD_CALLABLE_STR_1 402 +#define _GUARD_CALLABLE_TUPLE_1 403 +#define _GUARD_CALLABLE_TYPE_1 404 +#define _GUARD_DORV_NO_DICT 405 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 406 +#define _GUARD_GLOBALS_VERSION 407 +#define _GUARD_IP_RETURN_GENERATOR 408 +#define _GUARD_IP_RETURN_VALUE 409 +#define _GUARD_IP_YIELD_VALUE 410 +#define _GUARD_IP__PUSH_FRAME 411 +#define _GUARD_IS_FALSE_POP 412 +#define _GUARD_IS_NONE_POP 413 +#define _GUARD_IS_NOT_NONE_POP 414 +#define _GUARD_IS_TRUE_POP 415 +#define _GUARD_KEYS_VERSION 416 +#define _GUARD_NOS_COMPACT_ASCII 417 +#define _GUARD_NOS_DICT 418 +#define _GUARD_NOS_FLOAT 419 +#define _GUARD_NOS_INT 420 +#define _GUARD_NOS_LIST 421 +#define _GUARD_NOS_NOT_NULL 422 +#define _GUARD_NOS_NULL 423 +#define _GUARD_NOS_OVERFLOWED 424 +#define _GUARD_NOS_TUPLE 425 +#define _GUARD_NOS_UNICODE 426 +#define _GUARD_NOT_EXHAUSTED_LIST 427 +#define _GUARD_NOT_EXHAUSTED_RANGE 428 +#define _GUARD_NOT_EXHAUSTED_TUPLE 429 +#define _GUARD_THIRD_NULL 430 +#define _GUARD_TOS_ANY_SET 431 +#define _GUARD_TOS_DICT 432 +#define _GUARD_TOS_FLOAT 433 +#define _GUARD_TOS_INT 434 +#define _GUARD_TOS_LIST 435 +#define _GUARD_TOS_OVERFLOWED 436 +#define _GUARD_TOS_SLICE 437 +#define _GUARD_TOS_TUPLE 438 +#define _GUARD_TOS_UNICODE 439 +#define _GUARD_TYPE_VERSION 440 +#define _GUARD_TYPE_VERSION_AND_LOCK 441 +#define _HANDLE_PENDING_AND_DEOPT 442 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 433 -#define _INIT_CALL_PY_EXACT_ARGS 434 -#define _INIT_CALL_PY_EXACT_ARGS_0 435 -#define _INIT_CALL_PY_EXACT_ARGS_1 436 -#define _INIT_CALL_PY_EXACT_ARGS_2 437 -#define _INIT_CALL_PY_EXACT_ARGS_3 438 -#define _INIT_CALL_PY_EXACT_ARGS_4 439 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW 440 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW 441 -#define _INSERT_NULL 442 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 443 +#define _INIT_CALL_PY_EXACT_ARGS 444 +#define _INIT_CALL_PY_EXACT_ARGS_0 445 +#define _INIT_CALL_PY_EXACT_ARGS_1 446 +#define _INIT_CALL_PY_EXACT_ARGS_2 447 +#define _INIT_CALL_PY_EXACT_ARGS_3 448 +#define _INIT_CALL_PY_EXACT_ARGS_4 449 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW 450 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW 451 +#define _INSERT_NULL 452 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -196,995 +206,1035 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 443 -#define _IS_OP 444 -#define _ITER_CHECK_LIST 445 -#define _ITER_CHECK_RANGE 446 -#define _ITER_CHECK_TUPLE 447 -#define _ITER_JUMP_LIST 448 -#define _ITER_JUMP_RANGE 449 -#define _ITER_JUMP_TUPLE 450 -#define _ITER_NEXT_LIST 451 -#define _ITER_NEXT_LIST_TIER_TWO 452 -#define _ITER_NEXT_RANGE 453 -#define _ITER_NEXT_TUPLE 454 +#define _IS_NONE 453 +#define _IS_OP 454 +#define _ITER_CHECK_LIST 455 +#define _ITER_CHECK_RANGE 456 +#define _ITER_CHECK_TUPLE 457 +#define _ITER_JUMP_LIST 458 +#define _ITER_JUMP_RANGE 459 +#define _ITER_JUMP_TUPLE 460 +#define _ITER_NEXT_LIST 461 +#define _ITER_NEXT_LIST_TIER_TWO 462 +#define _ITER_NEXT_RANGE 463 +#define _ITER_NEXT_TUPLE 464 #define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT -#define _JUMP_TO_TOP 455 +#define _JUMP_TO_TOP 465 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 456 -#define _LOAD_ATTR_CLASS 457 +#define _LOAD_ATTR 466 +#define _LOAD_ATTR_CLASS 467 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 458 -#define _LOAD_ATTR_METHOD_LAZY_DICT 459 -#define _LOAD_ATTR_METHOD_NO_DICT 460 -#define _LOAD_ATTR_METHOD_WITH_VALUES 461 -#define _LOAD_ATTR_MODULE 462 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 463 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 464 -#define _LOAD_ATTR_PROPERTY_FRAME 465 -#define _LOAD_ATTR_SLOT 466 -#define _LOAD_ATTR_WITH_HINT 467 +#define _LOAD_ATTR_INSTANCE_VALUE 468 +#define _LOAD_ATTR_METHOD_LAZY_DICT 469 +#define _LOAD_ATTR_METHOD_NO_DICT 470 +#define _LOAD_ATTR_METHOD_WITH_VALUES 471 +#define _LOAD_ATTR_MODULE 472 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 473 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 474 +#define _LOAD_ATTR_PROPERTY_FRAME 475 +#define _LOAD_ATTR_SLOT 476 +#define _LOAD_ATTR_WITH_HINT 477 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 468 +#define _LOAD_BYTECODE 478 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 469 -#define _LOAD_CONST_INLINE_BORROW 470 -#define _LOAD_CONST_UNDER_INLINE 471 -#define _LOAD_CONST_UNDER_INLINE_BORROW 472 +#define _LOAD_CONST_INLINE 479 +#define _LOAD_CONST_INLINE_BORROW 480 +#define _LOAD_CONST_UNDER_INLINE 481 +#define _LOAD_CONST_UNDER_INLINE_BORROW 482 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 473 -#define _LOAD_FAST_0 474 -#define _LOAD_FAST_1 475 -#define _LOAD_FAST_2 476 -#define _LOAD_FAST_3 477 -#define _LOAD_FAST_4 478 -#define _LOAD_FAST_5 479 -#define _LOAD_FAST_6 480 -#define _LOAD_FAST_7 481 +#define _LOAD_FAST 483 +#define _LOAD_FAST_0 484 +#define _LOAD_FAST_1 485 +#define _LOAD_FAST_2 486 +#define _LOAD_FAST_3 487 +#define _LOAD_FAST_4 488 +#define _LOAD_FAST_5 489 +#define _LOAD_FAST_6 490 +#define _LOAD_FAST_7 491 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 482 -#define _LOAD_FAST_BORROW_0 483 -#define _LOAD_FAST_BORROW_1 484 -#define _LOAD_FAST_BORROW_2 485 -#define _LOAD_FAST_BORROW_3 486 -#define _LOAD_FAST_BORROW_4 487 -#define _LOAD_FAST_BORROW_5 488 -#define _LOAD_FAST_BORROW_6 489 -#define _LOAD_FAST_BORROW_7 490 +#define _LOAD_FAST_BORROW 492 +#define _LOAD_FAST_BORROW_0 493 +#define _LOAD_FAST_BORROW_1 494 +#define _LOAD_FAST_BORROW_2 495 +#define _LOAD_FAST_BORROW_3 496 +#define _LOAD_FAST_BORROW_4 497 +#define _LOAD_FAST_BORROW_5 498 +#define _LOAD_FAST_BORROW_6 499 +#define _LOAD_FAST_BORROW_7 500 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 491 -#define _LOAD_GLOBAL_BUILTINS 492 -#define _LOAD_GLOBAL_MODULE 493 +#define _LOAD_GLOBAL 501 +#define _LOAD_GLOBAL_BUILTINS 502 +#define _LOAD_GLOBAL_MODULE 503 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 494 -#define _LOAD_SMALL_INT_0 495 -#define _LOAD_SMALL_INT_1 496 -#define _LOAD_SMALL_INT_2 497 -#define _LOAD_SMALL_INT_3 498 -#define _LOAD_SPECIAL 499 +#define _LOAD_SMALL_INT 504 +#define _LOAD_SMALL_INT_0 505 +#define _LOAD_SMALL_INT_1 506 +#define _LOAD_SMALL_INT_2 507 +#define _LOAD_SMALL_INT_3 508 +#define _LOAD_SPECIAL 509 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 500 +#define _MAKE_CALLARGS_A_TUPLE 510 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 501 +#define _MAKE_WARM 511 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 502 -#define _MAYBE_EXPAND_METHOD_KW 503 -#define _MONITOR_CALL 504 -#define _MONITOR_CALL_KW 505 -#define _MONITOR_JUMP_BACKWARD 506 -#define _MONITOR_RESUME 507 +#define _MAYBE_EXPAND_METHOD 512 +#define _MAYBE_EXPAND_METHOD_KW 513 +#define _MONITOR_CALL 514 +#define _MONITOR_CALL_KW 515 +#define _MONITOR_JUMP_BACKWARD 516 +#define _MONITOR_RESUME 517 #define _NOP NOP -#define _POP_CALL 508 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW 509 -#define _POP_CALL_ONE 510 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 511 -#define _POP_CALL_TWO 512 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 513 +#define _POP_CALL 518 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW 519 +#define _POP_CALL_ONE 520 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 521 +#define _POP_CALL_TWO 522 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 523 #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 514 -#define _POP_JUMP_IF_TRUE 515 +#define _POP_JUMP_IF_FALSE 524 +#define _POP_JUMP_IF_TRUE 525 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 516 -#define _POP_TOP_INT 517 -#define _POP_TOP_LOAD_CONST_INLINE 518 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 519 -#define _POP_TOP_NOP 520 -#define _POP_TOP_UNICODE 521 -#define _POP_TWO 522 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 523 +#define _POP_TOP_FLOAT 526 +#define _POP_TOP_INT 527 +#define _POP_TOP_LOAD_CONST_INLINE 528 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 529 +#define _POP_TOP_NOP 530 +#define _POP_TOP_UNICODE 531 +#define _POP_TWO 532 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 533 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 524 +#define _PUSH_FRAME 534 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 525 -#define _PY_FRAME_EX 526 -#define _PY_FRAME_GENERAL 527 -#define _PY_FRAME_KW 528 -#define _QUICKEN_RESUME 529 -#define _REPLACE_WITH_TRUE 530 +#define _PUSH_NULL_CONDITIONAL 535 +#define _PY_FRAME_EX 536 +#define _PY_FRAME_GENERAL 537 +#define _PY_FRAME_KW 538 +#define _QUICKEN_RESUME 539 +#define _REPLACE_WITH_TRUE 540 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 531 -#define _SEND 532 -#define _SEND_GEN_FRAME 533 +#define _SAVE_RETURN_OFFSET 541 +#define _SEND 542 +#define _SEND_GEN_FRAME 543 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 534 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 535 -#define _SPILL_OR_RELOAD 536 -#define _START_EXECUTOR 537 -#define _STORE_ATTR 538 -#define _STORE_ATTR_INSTANCE_VALUE 539 -#define _STORE_ATTR_SLOT 540 -#define _STORE_ATTR_WITH_HINT 541 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 544 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 545 +#define _SPILL_OR_RELOAD 546 +#define _START_EXECUTOR 547 +#define _STORE_ATTR 548 +#define _STORE_ATTR_INSTANCE_VALUE 549 +#define _STORE_ATTR_SLOT 550 +#define _STORE_ATTR_WITH_HINT 551 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 542 -#define _STORE_SUBSCR 543 -#define _STORE_SUBSCR_DICT 544 -#define _STORE_SUBSCR_LIST_INT 545 -#define _SWAP 546 -#define _SWAP_2 547 -#define _SWAP_3 548 -#define _SWAP_FAST 549 -#define _SWAP_FAST_0 550 -#define _SWAP_FAST_1 551 -#define _SWAP_FAST_2 552 -#define _SWAP_FAST_3 553 -#define _SWAP_FAST_4 554 -#define _SWAP_FAST_5 555 -#define _SWAP_FAST_6 556 -#define _SWAP_FAST_7 557 -#define _TIER2_RESUME_CHECK 558 -#define _TO_BOOL 559 +#define _STORE_SLICE 552 +#define _STORE_SUBSCR 553 +#define _STORE_SUBSCR_DICT 554 +#define _STORE_SUBSCR_LIST_INT 555 +#define _SWAP 556 +#define _SWAP_2 557 +#define _SWAP_3 558 +#define _SWAP_FAST 559 +#define _SWAP_FAST_0 560 +#define _SWAP_FAST_1 561 +#define _SWAP_FAST_2 562 +#define _SWAP_FAST_3 563 +#define _SWAP_FAST_4 564 +#define _SWAP_FAST_5 565 +#define _SWAP_FAST_6 566 +#define _SWAP_FAST_7 567 +#define _TIER2_RESUME_CHECK 568 +#define _TO_BOOL 569 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 560 -#define _TO_BOOL_LIST 561 +#define _TO_BOOL_INT 570 +#define _TO_BOOL_LIST 571 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 562 +#define _TO_BOOL_STR 572 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 563 -#define _UNARY_NEGATIVE 564 +#define _UNARY_INVERT 573 +#define _UNARY_NEGATIVE 574 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 565 -#define _UNPACK_SEQUENCE_LIST 566 -#define _UNPACK_SEQUENCE_TUPLE 567 -#define _UNPACK_SEQUENCE_TWO_TUPLE 568 +#define _UNPACK_SEQUENCE 575 +#define _UNPACK_SEQUENCE_LIST 576 +#define _UNPACK_SEQUENCE_TUPLE 577 +#define _UNPACK_SEQUENCE_TWO_TUPLE 578 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 568 -#define _BINARY_OP_r21 569 -#define _BINARY_OP_ADD_FLOAT_r03 570 -#define _BINARY_OP_ADD_FLOAT_r13 571 -#define _BINARY_OP_ADD_FLOAT_r23 572 -#define _BINARY_OP_ADD_INT_r03 573 -#define _BINARY_OP_ADD_INT_r13 574 -#define _BINARY_OP_ADD_INT_r23 575 -#define _BINARY_OP_ADD_UNICODE_r03 576 -#define _BINARY_OP_ADD_UNICODE_r13 577 -#define _BINARY_OP_ADD_UNICODE_r23 578 -#define _BINARY_OP_EXTEND_r21 579 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 580 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 581 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 582 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 583 -#define _BINARY_OP_MULTIPLY_INT_r03 584 -#define _BINARY_OP_MULTIPLY_INT_r13 585 -#define _BINARY_OP_MULTIPLY_INT_r23 586 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 587 -#define _BINARY_OP_SUBSCR_DICT_r23 588 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 589 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 590 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 591 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 592 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 593 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 594 -#define _BINARY_OP_SUBSCR_STR_INT_r23 595 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 596 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 597 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 598 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 599 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 600 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 601 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 602 -#define _BINARY_OP_SUBTRACT_INT_r03 603 -#define _BINARY_OP_SUBTRACT_INT_r13 604 -#define _BINARY_OP_SUBTRACT_INT_r23 605 -#define _BINARY_SLICE_r31 606 -#define _BUILD_INTERPOLATION_r01 607 -#define _BUILD_LIST_r01 608 -#define _BUILD_MAP_r01 609 -#define _BUILD_SET_r01 610 -#define _BUILD_SLICE_r01 611 -#define _BUILD_STRING_r01 612 -#define _BUILD_TEMPLATE_r21 613 -#define _BUILD_TUPLE_r01 614 -#define _CALL_BUILTIN_CLASS_r01 615 -#define _CALL_BUILTIN_FAST_r01 616 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 617 -#define _CALL_BUILTIN_O_r03 618 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 619 -#define _CALL_INTRINSIC_1_r11 620 -#define _CALL_INTRINSIC_2_r21 621 -#define _CALL_ISINSTANCE_r31 622 -#define _CALL_KW_NON_PY_r11 623 -#define _CALL_LEN_r33 624 -#define _CALL_LIST_APPEND_r03 625 -#define _CALL_LIST_APPEND_r13 626 -#define _CALL_LIST_APPEND_r23 627 -#define _CALL_LIST_APPEND_r33 628 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 629 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 630 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 631 -#define _CALL_METHOD_DESCRIPTOR_O_r03 632 -#define _CALL_NON_PY_GENERAL_r01 633 -#define _CALL_STR_1_r32 634 -#define _CALL_TUPLE_1_r32 635 -#define _CALL_TYPE_1_r02 636 -#define _CALL_TYPE_1_r12 637 -#define _CALL_TYPE_1_r22 638 -#define _CALL_TYPE_1_r32 639 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 640 -#define _CHECK_ATTR_CLASS_r01 641 -#define _CHECK_ATTR_CLASS_r11 642 -#define _CHECK_ATTR_CLASS_r22 643 -#define _CHECK_ATTR_CLASS_r33 644 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 645 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 646 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 647 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 648 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 649 -#define _CHECK_EG_MATCH_r22 650 -#define _CHECK_EXC_MATCH_r22 651 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 652 -#define _CHECK_FUNCTION_VERSION_r00 653 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 654 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 655 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 656 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 657 -#define _CHECK_FUNCTION_VERSION_KW_r11 658 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 659 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 660 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 661 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 662 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 663 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 664 -#define _CHECK_IS_PY_CALLABLE_EX_r03 665 -#define _CHECK_IS_PY_CALLABLE_EX_r13 666 -#define _CHECK_IS_PY_CALLABLE_EX_r23 667 -#define _CHECK_IS_PY_CALLABLE_EX_r33 668 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 669 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 670 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 671 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 672 -#define _CHECK_METHOD_VERSION_r00 673 -#define _CHECK_METHOD_VERSION_KW_r11 674 -#define _CHECK_PEP_523_r00 675 -#define _CHECK_PEP_523_r11 676 -#define _CHECK_PEP_523_r22 677 -#define _CHECK_PEP_523_r33 678 -#define _CHECK_PERIODIC_r00 679 -#define _CHECK_PERIODIC_AT_END_r00 680 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 681 -#define _CHECK_RECURSION_REMAINING_r00 682 -#define _CHECK_RECURSION_REMAINING_r11 683 -#define _CHECK_RECURSION_REMAINING_r22 684 -#define _CHECK_RECURSION_REMAINING_r33 685 -#define _CHECK_STACK_SPACE_r00 686 -#define _CHECK_STACK_SPACE_OPERAND_r00 687 -#define _CHECK_STACK_SPACE_OPERAND_r11 688 -#define _CHECK_STACK_SPACE_OPERAND_r22 689 -#define _CHECK_STACK_SPACE_OPERAND_r33 690 -#define _CHECK_VALIDITY_r00 691 -#define _CHECK_VALIDITY_r11 692 -#define _CHECK_VALIDITY_r22 693 -#define _CHECK_VALIDITY_r33 694 -#define _COLD_DYNAMIC_EXIT_r00 695 -#define _COLD_EXIT_r00 696 -#define _COMPARE_OP_r21 697 -#define _COMPARE_OP_FLOAT_r03 698 -#define _COMPARE_OP_FLOAT_r13 699 -#define _COMPARE_OP_FLOAT_r23 700 -#define _COMPARE_OP_INT_r23 701 -#define _COMPARE_OP_STR_r23 702 -#define _CONTAINS_OP_r23 703 -#define _CONTAINS_OP_DICT_r23 704 -#define _CONTAINS_OP_SET_r23 705 -#define _CONVERT_VALUE_r11 706 -#define _COPY_r01 707 -#define _COPY_1_r02 708 -#define _COPY_1_r12 709 -#define _COPY_1_r23 710 -#define _COPY_2_r03 711 -#define _COPY_2_r13 712 -#define _COPY_2_r23 713 -#define _COPY_3_r03 714 -#define _COPY_3_r13 715 -#define _COPY_3_r23 716 -#define _COPY_3_r33 717 -#define _COPY_FREE_VARS_r00 718 -#define _COPY_FREE_VARS_r11 719 -#define _COPY_FREE_VARS_r22 720 -#define _COPY_FREE_VARS_r33 721 -#define _CREATE_INIT_FRAME_r01 722 -#define _DELETE_ATTR_r10 723 -#define _DELETE_DEREF_r00 724 -#define _DELETE_FAST_r00 725 -#define _DELETE_GLOBAL_r00 726 -#define _DELETE_NAME_r00 727 -#define _DELETE_SUBSCR_r20 728 -#define _DEOPT_r00 729 -#define _DEOPT_r10 730 -#define _DEOPT_r20 731 -#define _DEOPT_r30 732 -#define _DICT_MERGE_r10 733 -#define _DICT_UPDATE_r10 734 -#define _DO_CALL_r01 735 -#define _DO_CALL_FUNCTION_EX_r31 736 -#define _DO_CALL_KW_r11 737 -#define _DYNAMIC_EXIT_r00 738 -#define _DYNAMIC_EXIT_r10 739 -#define _DYNAMIC_EXIT_r20 740 -#define _DYNAMIC_EXIT_r30 741 -#define _END_FOR_r10 742 -#define _END_SEND_r21 743 -#define _ERROR_POP_N_r00 744 -#define _EXIT_INIT_CHECK_r10 745 -#define _EXIT_TRACE_r00 746 -#define _EXIT_TRACE_r10 747 -#define _EXIT_TRACE_r20 748 -#define _EXIT_TRACE_r30 749 -#define _EXPAND_METHOD_r00 750 -#define _EXPAND_METHOD_KW_r11 751 -#define _FATAL_ERROR_r00 752 -#define _FATAL_ERROR_r11 753 -#define _FATAL_ERROR_r22 754 -#define _FATAL_ERROR_r33 755 -#define _FORMAT_SIMPLE_r11 756 -#define _FORMAT_WITH_SPEC_r21 757 -#define _FOR_ITER_r23 758 -#define _FOR_ITER_GEN_FRAME_r03 759 -#define _FOR_ITER_GEN_FRAME_r13 760 -#define _FOR_ITER_GEN_FRAME_r23 761 -#define _FOR_ITER_TIER_TWO_r23 762 -#define _GET_AITER_r11 763 -#define _GET_ANEXT_r12 764 -#define _GET_AWAITABLE_r11 765 -#define _GET_ITER_r12 766 -#define _GET_LEN_r12 767 -#define _GET_YIELD_FROM_ITER_r11 768 -#define _GUARD_BINARY_OP_EXTEND_r22 769 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 770 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 771 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 772 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 773 -#define _GUARD_CALLABLE_ISINSTANCE_r03 774 -#define _GUARD_CALLABLE_ISINSTANCE_r13 775 -#define _GUARD_CALLABLE_ISINSTANCE_r23 776 -#define _GUARD_CALLABLE_ISINSTANCE_r33 777 -#define _GUARD_CALLABLE_LEN_r03 778 -#define _GUARD_CALLABLE_LEN_r13 779 -#define _GUARD_CALLABLE_LEN_r23 780 -#define _GUARD_CALLABLE_LEN_r33 781 -#define _GUARD_CALLABLE_LIST_APPEND_r03 782 -#define _GUARD_CALLABLE_LIST_APPEND_r13 783 -#define _GUARD_CALLABLE_LIST_APPEND_r23 784 -#define _GUARD_CALLABLE_LIST_APPEND_r33 785 -#define _GUARD_CALLABLE_STR_1_r03 786 -#define _GUARD_CALLABLE_STR_1_r13 787 -#define _GUARD_CALLABLE_STR_1_r23 788 -#define _GUARD_CALLABLE_STR_1_r33 789 -#define _GUARD_CALLABLE_TUPLE_1_r03 790 -#define _GUARD_CALLABLE_TUPLE_1_r13 791 -#define _GUARD_CALLABLE_TUPLE_1_r23 792 -#define _GUARD_CALLABLE_TUPLE_1_r33 793 -#define _GUARD_CALLABLE_TYPE_1_r03 794 -#define _GUARD_CALLABLE_TYPE_1_r13 795 -#define _GUARD_CALLABLE_TYPE_1_r23 796 -#define _GUARD_CALLABLE_TYPE_1_r33 797 -#define _GUARD_DORV_NO_DICT_r01 798 -#define _GUARD_DORV_NO_DICT_r11 799 -#define _GUARD_DORV_NO_DICT_r22 800 -#define _GUARD_DORV_NO_DICT_r33 801 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 802 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 803 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 804 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 805 -#define _GUARD_GLOBALS_VERSION_r00 806 -#define _GUARD_GLOBALS_VERSION_r11 807 -#define _GUARD_GLOBALS_VERSION_r22 808 -#define _GUARD_GLOBALS_VERSION_r33 809 -#define _GUARD_IP_RETURN_GENERATOR_r00 810 -#define _GUARD_IP_RETURN_GENERATOR_r11 811 -#define _GUARD_IP_RETURN_GENERATOR_r22 812 -#define _GUARD_IP_RETURN_GENERATOR_r33 813 -#define _GUARD_IP_RETURN_VALUE_r00 814 -#define _GUARD_IP_RETURN_VALUE_r11 815 -#define _GUARD_IP_RETURN_VALUE_r22 816 -#define _GUARD_IP_RETURN_VALUE_r33 817 -#define _GUARD_IP_YIELD_VALUE_r00 818 -#define _GUARD_IP_YIELD_VALUE_r11 819 -#define _GUARD_IP_YIELD_VALUE_r22 820 -#define _GUARD_IP_YIELD_VALUE_r33 821 -#define _GUARD_IP__PUSH_FRAME_r00 822 -#define _GUARD_IP__PUSH_FRAME_r11 823 -#define _GUARD_IP__PUSH_FRAME_r22 824 -#define _GUARD_IP__PUSH_FRAME_r33 825 -#define _GUARD_IS_FALSE_POP_r00 826 -#define _GUARD_IS_FALSE_POP_r10 827 -#define _GUARD_IS_FALSE_POP_r21 828 -#define _GUARD_IS_FALSE_POP_r32 829 -#define _GUARD_IS_NONE_POP_r00 830 -#define _GUARD_IS_NONE_POP_r10 831 -#define _GUARD_IS_NONE_POP_r21 832 -#define _GUARD_IS_NONE_POP_r32 833 -#define _GUARD_IS_NOT_NONE_POP_r10 834 -#define _GUARD_IS_TRUE_POP_r00 835 -#define _GUARD_IS_TRUE_POP_r10 836 -#define _GUARD_IS_TRUE_POP_r21 837 -#define _GUARD_IS_TRUE_POP_r32 838 -#define _GUARD_KEYS_VERSION_r01 839 -#define _GUARD_KEYS_VERSION_r11 840 -#define _GUARD_KEYS_VERSION_r22 841 -#define _GUARD_KEYS_VERSION_r33 842 -#define _GUARD_NOS_COMPACT_ASCII_r02 843 -#define _GUARD_NOS_COMPACT_ASCII_r12 844 -#define _GUARD_NOS_COMPACT_ASCII_r22 845 -#define _GUARD_NOS_COMPACT_ASCII_r33 846 -#define _GUARD_NOS_DICT_r02 847 -#define _GUARD_NOS_DICT_r12 848 -#define _GUARD_NOS_DICT_r22 849 -#define _GUARD_NOS_DICT_r33 850 -#define _GUARD_NOS_FLOAT_r02 851 -#define _GUARD_NOS_FLOAT_r12 852 -#define _GUARD_NOS_FLOAT_r22 853 -#define _GUARD_NOS_FLOAT_r33 854 -#define _GUARD_NOS_INT_r02 855 -#define _GUARD_NOS_INT_r12 856 -#define _GUARD_NOS_INT_r22 857 -#define _GUARD_NOS_INT_r33 858 -#define _GUARD_NOS_LIST_r02 859 -#define _GUARD_NOS_LIST_r12 860 -#define _GUARD_NOS_LIST_r22 861 -#define _GUARD_NOS_LIST_r33 862 -#define _GUARD_NOS_NOT_NULL_r02 863 -#define _GUARD_NOS_NOT_NULL_r12 864 -#define _GUARD_NOS_NOT_NULL_r22 865 -#define _GUARD_NOS_NOT_NULL_r33 866 -#define _GUARD_NOS_NULL_r02 867 -#define _GUARD_NOS_NULL_r12 868 -#define _GUARD_NOS_NULL_r22 869 -#define _GUARD_NOS_NULL_r33 870 -#define _GUARD_NOS_OVERFLOWED_r02 871 -#define _GUARD_NOS_OVERFLOWED_r12 872 -#define _GUARD_NOS_OVERFLOWED_r22 873 -#define _GUARD_NOS_OVERFLOWED_r33 874 -#define _GUARD_NOS_TUPLE_r02 875 -#define _GUARD_NOS_TUPLE_r12 876 -#define _GUARD_NOS_TUPLE_r22 877 -#define _GUARD_NOS_TUPLE_r33 878 -#define _GUARD_NOS_UNICODE_r02 879 -#define _GUARD_NOS_UNICODE_r12 880 -#define _GUARD_NOS_UNICODE_r22 881 -#define _GUARD_NOS_UNICODE_r33 882 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 883 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 884 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 885 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 886 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 887 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 888 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 889 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 890 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 891 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 892 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 893 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 894 -#define _GUARD_THIRD_NULL_r03 895 -#define _GUARD_THIRD_NULL_r13 896 -#define _GUARD_THIRD_NULL_r23 897 -#define _GUARD_THIRD_NULL_r33 898 -#define _GUARD_TOS_ANY_SET_r01 899 -#define _GUARD_TOS_ANY_SET_r11 900 -#define _GUARD_TOS_ANY_SET_r22 901 -#define _GUARD_TOS_ANY_SET_r33 902 -#define _GUARD_TOS_DICT_r01 903 -#define _GUARD_TOS_DICT_r11 904 -#define _GUARD_TOS_DICT_r22 905 -#define _GUARD_TOS_DICT_r33 906 -#define _GUARD_TOS_FLOAT_r01 907 -#define _GUARD_TOS_FLOAT_r11 908 -#define _GUARD_TOS_FLOAT_r22 909 -#define _GUARD_TOS_FLOAT_r33 910 -#define _GUARD_TOS_INT_r01 911 -#define _GUARD_TOS_INT_r11 912 -#define _GUARD_TOS_INT_r22 913 -#define _GUARD_TOS_INT_r33 914 -#define _GUARD_TOS_LIST_r01 915 -#define _GUARD_TOS_LIST_r11 916 -#define _GUARD_TOS_LIST_r22 917 -#define _GUARD_TOS_LIST_r33 918 -#define _GUARD_TOS_OVERFLOWED_r01 919 -#define _GUARD_TOS_OVERFLOWED_r11 920 -#define _GUARD_TOS_OVERFLOWED_r22 921 -#define _GUARD_TOS_OVERFLOWED_r33 922 -#define _GUARD_TOS_SLICE_r01 923 -#define _GUARD_TOS_SLICE_r11 924 -#define _GUARD_TOS_SLICE_r22 925 -#define _GUARD_TOS_SLICE_r33 926 -#define _GUARD_TOS_TUPLE_r01 927 -#define _GUARD_TOS_TUPLE_r11 928 -#define _GUARD_TOS_TUPLE_r22 929 -#define _GUARD_TOS_TUPLE_r33 930 -#define _GUARD_TOS_UNICODE_r01 931 -#define _GUARD_TOS_UNICODE_r11 932 -#define _GUARD_TOS_UNICODE_r22 933 -#define _GUARD_TOS_UNICODE_r33 934 -#define _GUARD_TYPE_VERSION_r01 935 -#define _GUARD_TYPE_VERSION_r11 936 -#define _GUARD_TYPE_VERSION_r22 937 -#define _GUARD_TYPE_VERSION_r33 938 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 939 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 940 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 941 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 942 -#define _HANDLE_PENDING_AND_DEOPT_r00 943 -#define _HANDLE_PENDING_AND_DEOPT_r10 944 -#define _HANDLE_PENDING_AND_DEOPT_r20 945 -#define _HANDLE_PENDING_AND_DEOPT_r30 946 -#define _IMPORT_FROM_r12 947 -#define _IMPORT_NAME_r21 948 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 949 -#define _INIT_CALL_PY_EXACT_ARGS_r01 950 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 951 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 952 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 953 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 954 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 955 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 956 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 957 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 958 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 959 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 960 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 961 -#define _INSERT_NULL_r10 962 -#define _INSTRUMENTED_FOR_ITER_r23 963 -#define _INSTRUMENTED_INSTRUCTION_r00 964 -#define _INSTRUMENTED_JUMP_FORWARD_r00 965 -#define _INSTRUMENTED_JUMP_FORWARD_r11 966 -#define _INSTRUMENTED_JUMP_FORWARD_r22 967 -#define _INSTRUMENTED_JUMP_FORWARD_r33 968 -#define _INSTRUMENTED_LINE_r00 969 -#define _INSTRUMENTED_NOT_TAKEN_r00 970 -#define _INSTRUMENTED_NOT_TAKEN_r11 971 -#define _INSTRUMENTED_NOT_TAKEN_r22 972 -#define _INSTRUMENTED_NOT_TAKEN_r33 973 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 974 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 975 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 976 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 977 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 978 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 979 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 980 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 981 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 982 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 983 -#define _IS_NONE_r11 984 -#define _IS_OP_r03 985 -#define _IS_OP_r13 986 -#define _IS_OP_r23 987 -#define _ITER_CHECK_LIST_r02 988 -#define _ITER_CHECK_LIST_r12 989 -#define _ITER_CHECK_LIST_r22 990 -#define _ITER_CHECK_LIST_r33 991 -#define _ITER_CHECK_RANGE_r02 992 -#define _ITER_CHECK_RANGE_r12 993 -#define _ITER_CHECK_RANGE_r22 994 -#define _ITER_CHECK_RANGE_r33 995 -#define _ITER_CHECK_TUPLE_r02 996 -#define _ITER_CHECK_TUPLE_r12 997 -#define _ITER_CHECK_TUPLE_r22 998 -#define _ITER_CHECK_TUPLE_r33 999 -#define _ITER_JUMP_LIST_r02 1000 -#define _ITER_JUMP_LIST_r12 1001 -#define _ITER_JUMP_LIST_r22 1002 -#define _ITER_JUMP_LIST_r33 1003 -#define _ITER_JUMP_RANGE_r02 1004 -#define _ITER_JUMP_RANGE_r12 1005 -#define _ITER_JUMP_RANGE_r22 1006 -#define _ITER_JUMP_RANGE_r33 1007 -#define _ITER_JUMP_TUPLE_r02 1008 -#define _ITER_JUMP_TUPLE_r12 1009 -#define _ITER_JUMP_TUPLE_r22 1010 -#define _ITER_JUMP_TUPLE_r33 1011 -#define _ITER_NEXT_LIST_r23 1012 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1013 -#define _ITER_NEXT_RANGE_r03 1014 -#define _ITER_NEXT_RANGE_r13 1015 -#define _ITER_NEXT_RANGE_r23 1016 -#define _ITER_NEXT_TUPLE_r03 1017 -#define _ITER_NEXT_TUPLE_r13 1018 -#define _ITER_NEXT_TUPLE_r23 1019 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1020 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1021 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1022 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1023 -#define _JUMP_TO_TOP_r00 1024 -#define _LIST_APPEND_r10 1025 -#define _LIST_EXTEND_r10 1026 -#define _LOAD_ATTR_r10 1027 -#define _LOAD_ATTR_CLASS_r11 1028 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1029 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1030 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1031 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1032 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1033 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1034 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1035 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1036 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1037 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1038 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1039 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1040 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1041 -#define _LOAD_ATTR_MODULE_r11 1042 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1043 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1044 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1045 -#define _LOAD_ATTR_SLOT_r02 1046 -#define _LOAD_ATTR_SLOT_r12 1047 -#define _LOAD_ATTR_SLOT_r23 1048 -#define _LOAD_ATTR_WITH_HINT_r12 1049 -#define _LOAD_BUILD_CLASS_r01 1050 -#define _LOAD_BYTECODE_r00 1051 -#define _LOAD_COMMON_CONSTANT_r01 1052 -#define _LOAD_COMMON_CONSTANT_r12 1053 -#define _LOAD_COMMON_CONSTANT_r23 1054 -#define _LOAD_CONST_r01 1055 -#define _LOAD_CONST_r12 1056 -#define _LOAD_CONST_r23 1057 -#define _LOAD_CONST_INLINE_r01 1058 -#define _LOAD_CONST_INLINE_r12 1059 -#define _LOAD_CONST_INLINE_r23 1060 -#define _LOAD_CONST_INLINE_BORROW_r01 1061 -#define _LOAD_CONST_INLINE_BORROW_r12 1062 -#define _LOAD_CONST_INLINE_BORROW_r23 1063 -#define _LOAD_CONST_UNDER_INLINE_r02 1064 -#define _LOAD_CONST_UNDER_INLINE_r12 1065 -#define _LOAD_CONST_UNDER_INLINE_r23 1066 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1067 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1068 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1069 -#define _LOAD_DEREF_r01 1070 -#define _LOAD_FAST_r01 1071 -#define _LOAD_FAST_r12 1072 -#define _LOAD_FAST_r23 1073 -#define _LOAD_FAST_0_r01 1074 -#define _LOAD_FAST_0_r12 1075 -#define _LOAD_FAST_0_r23 1076 -#define _LOAD_FAST_1_r01 1077 -#define _LOAD_FAST_1_r12 1078 -#define _LOAD_FAST_1_r23 1079 -#define _LOAD_FAST_2_r01 1080 -#define _LOAD_FAST_2_r12 1081 -#define _LOAD_FAST_2_r23 1082 -#define _LOAD_FAST_3_r01 1083 -#define _LOAD_FAST_3_r12 1084 -#define _LOAD_FAST_3_r23 1085 -#define _LOAD_FAST_4_r01 1086 -#define _LOAD_FAST_4_r12 1087 -#define _LOAD_FAST_4_r23 1088 -#define _LOAD_FAST_5_r01 1089 -#define _LOAD_FAST_5_r12 1090 -#define _LOAD_FAST_5_r23 1091 -#define _LOAD_FAST_6_r01 1092 -#define _LOAD_FAST_6_r12 1093 -#define _LOAD_FAST_6_r23 1094 -#define _LOAD_FAST_7_r01 1095 -#define _LOAD_FAST_7_r12 1096 -#define _LOAD_FAST_7_r23 1097 -#define _LOAD_FAST_AND_CLEAR_r01 1098 -#define _LOAD_FAST_AND_CLEAR_r12 1099 -#define _LOAD_FAST_AND_CLEAR_r23 1100 -#define _LOAD_FAST_BORROW_r01 1101 -#define _LOAD_FAST_BORROW_r12 1102 -#define _LOAD_FAST_BORROW_r23 1103 -#define _LOAD_FAST_BORROW_0_r01 1104 -#define _LOAD_FAST_BORROW_0_r12 1105 -#define _LOAD_FAST_BORROW_0_r23 1106 -#define _LOAD_FAST_BORROW_1_r01 1107 -#define _LOAD_FAST_BORROW_1_r12 1108 -#define _LOAD_FAST_BORROW_1_r23 1109 -#define _LOAD_FAST_BORROW_2_r01 1110 -#define _LOAD_FAST_BORROW_2_r12 1111 -#define _LOAD_FAST_BORROW_2_r23 1112 -#define _LOAD_FAST_BORROW_3_r01 1113 -#define _LOAD_FAST_BORROW_3_r12 1114 -#define _LOAD_FAST_BORROW_3_r23 1115 -#define _LOAD_FAST_BORROW_4_r01 1116 -#define _LOAD_FAST_BORROW_4_r12 1117 -#define _LOAD_FAST_BORROW_4_r23 1118 -#define _LOAD_FAST_BORROW_5_r01 1119 -#define _LOAD_FAST_BORROW_5_r12 1120 -#define _LOAD_FAST_BORROW_5_r23 1121 -#define _LOAD_FAST_BORROW_6_r01 1122 -#define _LOAD_FAST_BORROW_6_r12 1123 -#define _LOAD_FAST_BORROW_6_r23 1124 -#define _LOAD_FAST_BORROW_7_r01 1125 -#define _LOAD_FAST_BORROW_7_r12 1126 -#define _LOAD_FAST_BORROW_7_r23 1127 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1128 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1129 -#define _LOAD_FAST_CHECK_r01 1130 -#define _LOAD_FAST_CHECK_r12 1131 -#define _LOAD_FAST_CHECK_r23 1132 -#define _LOAD_FAST_LOAD_FAST_r02 1133 -#define _LOAD_FAST_LOAD_FAST_r13 1134 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1135 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1136 -#define _LOAD_GLOBAL_r00 1137 -#define _LOAD_GLOBAL_BUILTINS_r01 1138 -#define _LOAD_GLOBAL_MODULE_r01 1139 -#define _LOAD_LOCALS_r01 1140 -#define _LOAD_LOCALS_r12 1141 -#define _LOAD_LOCALS_r23 1142 -#define _LOAD_NAME_r01 1143 -#define _LOAD_SMALL_INT_r01 1144 -#define _LOAD_SMALL_INT_r12 1145 -#define _LOAD_SMALL_INT_r23 1146 -#define _LOAD_SMALL_INT_0_r01 1147 -#define _LOAD_SMALL_INT_0_r12 1148 -#define _LOAD_SMALL_INT_0_r23 1149 -#define _LOAD_SMALL_INT_1_r01 1150 -#define _LOAD_SMALL_INT_1_r12 1151 -#define _LOAD_SMALL_INT_1_r23 1152 -#define _LOAD_SMALL_INT_2_r01 1153 -#define _LOAD_SMALL_INT_2_r12 1154 -#define _LOAD_SMALL_INT_2_r23 1155 -#define _LOAD_SMALL_INT_3_r01 1156 -#define _LOAD_SMALL_INT_3_r12 1157 -#define _LOAD_SMALL_INT_3_r23 1158 -#define _LOAD_SPECIAL_r00 1159 -#define _LOAD_SUPER_ATTR_ATTR_r31 1160 -#define _LOAD_SUPER_ATTR_METHOD_r32 1161 -#define _MAKE_CALLARGS_A_TUPLE_r33 1162 -#define _MAKE_CELL_r00 1163 -#define _MAKE_FUNCTION_r11 1164 -#define _MAKE_WARM_r00 1165 -#define _MAKE_WARM_r11 1166 -#define _MAKE_WARM_r22 1167 -#define _MAKE_WARM_r33 1168 -#define _MAP_ADD_r20 1169 -#define _MATCH_CLASS_r31 1170 -#define _MATCH_KEYS_r23 1171 -#define _MATCH_MAPPING_r02 1172 -#define _MATCH_MAPPING_r12 1173 -#define _MATCH_MAPPING_r23 1174 -#define _MATCH_SEQUENCE_r02 1175 -#define _MATCH_SEQUENCE_r12 1176 -#define _MATCH_SEQUENCE_r23 1177 -#define _MAYBE_EXPAND_METHOD_r00 1178 -#define _MAYBE_EXPAND_METHOD_KW_r11 1179 -#define _MONITOR_CALL_r00 1180 -#define _MONITOR_CALL_KW_r11 1181 -#define _MONITOR_JUMP_BACKWARD_r00 1182 -#define _MONITOR_JUMP_BACKWARD_r11 1183 -#define _MONITOR_JUMP_BACKWARD_r22 1184 -#define _MONITOR_JUMP_BACKWARD_r33 1185 -#define _MONITOR_RESUME_r00 1186 -#define _NOP_r00 1187 -#define _NOP_r11 1188 -#define _NOP_r22 1189 -#define _NOP_r33 1190 -#define _POP_CALL_r20 1191 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1192 -#define _POP_CALL_ONE_r30 1193 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1194 -#define _POP_CALL_TWO_r30 1195 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1196 -#define _POP_EXCEPT_r10 1197 -#define _POP_ITER_r20 1198 -#define _POP_JUMP_IF_FALSE_r00 1199 -#define _POP_JUMP_IF_FALSE_r10 1200 -#define _POP_JUMP_IF_FALSE_r21 1201 -#define _POP_JUMP_IF_FALSE_r32 1202 -#define _POP_JUMP_IF_TRUE_r00 1203 -#define _POP_JUMP_IF_TRUE_r10 1204 -#define _POP_JUMP_IF_TRUE_r21 1205 -#define _POP_JUMP_IF_TRUE_r32 1206 -#define _POP_TOP_r10 1207 -#define _POP_TOP_FLOAT_r00 1208 -#define _POP_TOP_FLOAT_r10 1209 -#define _POP_TOP_FLOAT_r21 1210 -#define _POP_TOP_FLOAT_r32 1211 -#define _POP_TOP_INT_r00 1212 -#define _POP_TOP_INT_r10 1213 -#define _POP_TOP_INT_r21 1214 -#define _POP_TOP_INT_r32 1215 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1216 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1217 -#define _POP_TOP_NOP_r00 1218 -#define _POP_TOP_NOP_r10 1219 -#define _POP_TOP_NOP_r21 1220 -#define _POP_TOP_NOP_r32 1221 -#define _POP_TOP_UNICODE_r00 1222 -#define _POP_TOP_UNICODE_r10 1223 -#define _POP_TOP_UNICODE_r21 1224 -#define _POP_TOP_UNICODE_r32 1225 -#define _POP_TWO_r20 1226 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1227 -#define _PUSH_EXC_INFO_r02 1228 -#define _PUSH_EXC_INFO_r12 1229 -#define _PUSH_EXC_INFO_r23 1230 -#define _PUSH_FRAME_r10 1231 -#define _PUSH_NULL_r01 1232 -#define _PUSH_NULL_r12 1233 -#define _PUSH_NULL_r23 1234 -#define _PUSH_NULL_CONDITIONAL_r00 1235 -#define _PY_FRAME_EX_r31 1236 -#define _PY_FRAME_GENERAL_r01 1237 -#define _PY_FRAME_KW_r11 1238 -#define _QUICKEN_RESUME_r00 1239 -#define _QUICKEN_RESUME_r11 1240 -#define _QUICKEN_RESUME_r22 1241 -#define _QUICKEN_RESUME_r33 1242 -#define _REPLACE_WITH_TRUE_r02 1243 -#define _REPLACE_WITH_TRUE_r12 1244 -#define _REPLACE_WITH_TRUE_r23 1245 -#define _RESUME_CHECK_r00 1246 -#define _RESUME_CHECK_r11 1247 -#define _RESUME_CHECK_r22 1248 -#define _RESUME_CHECK_r33 1249 -#define _RETURN_GENERATOR_r01 1250 -#define _RETURN_VALUE_r11 1251 -#define _SAVE_RETURN_OFFSET_r00 1252 -#define _SAVE_RETURN_OFFSET_r11 1253 -#define _SAVE_RETURN_OFFSET_r22 1254 -#define _SAVE_RETURN_OFFSET_r33 1255 -#define _SEND_r22 1256 -#define _SEND_GEN_FRAME_r22 1257 -#define _SETUP_ANNOTATIONS_r00 1258 -#define _SET_ADD_r10 1259 -#define _SET_FUNCTION_ATTRIBUTE_r01 1260 -#define _SET_FUNCTION_ATTRIBUTE_r11 1261 -#define _SET_FUNCTION_ATTRIBUTE_r21 1262 -#define _SET_FUNCTION_ATTRIBUTE_r32 1263 -#define _SET_IP_r00 1264 -#define _SET_IP_r11 1265 -#define _SET_IP_r22 1266 -#define _SET_IP_r33 1267 -#define _SET_UPDATE_r10 1268 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1269 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1270 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1271 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1272 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1273 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1274 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1275 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1276 -#define _SPILL_OR_RELOAD_r01 1277 -#define _SPILL_OR_RELOAD_r02 1278 -#define _SPILL_OR_RELOAD_r03 1279 -#define _SPILL_OR_RELOAD_r10 1280 -#define _SPILL_OR_RELOAD_r12 1281 -#define _SPILL_OR_RELOAD_r13 1282 -#define _SPILL_OR_RELOAD_r20 1283 -#define _SPILL_OR_RELOAD_r21 1284 -#define _SPILL_OR_RELOAD_r23 1285 -#define _SPILL_OR_RELOAD_r30 1286 -#define _SPILL_OR_RELOAD_r31 1287 -#define _SPILL_OR_RELOAD_r32 1288 -#define _START_EXECUTOR_r00 1289 -#define _STORE_ATTR_r20 1290 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1291 -#define _STORE_ATTR_SLOT_r21 1292 -#define _STORE_ATTR_WITH_HINT_r21 1293 -#define _STORE_DEREF_r10 1294 -#define _STORE_FAST_LOAD_FAST_r11 1295 -#define _STORE_FAST_STORE_FAST_r20 1296 -#define _STORE_GLOBAL_r10 1297 -#define _STORE_NAME_r10 1298 -#define _STORE_SLICE_r30 1299 -#define _STORE_SUBSCR_r30 1300 -#define _STORE_SUBSCR_DICT_r31 1301 -#define _STORE_SUBSCR_LIST_INT_r32 1302 -#define _SWAP_r11 1303 -#define _SWAP_2_r02 1304 -#define _SWAP_2_r12 1305 -#define _SWAP_2_r22 1306 -#define _SWAP_2_r33 1307 -#define _SWAP_3_r03 1308 -#define _SWAP_3_r13 1309 -#define _SWAP_3_r23 1310 -#define _SWAP_3_r33 1311 -#define _SWAP_FAST_r01 1312 -#define _SWAP_FAST_r11 1313 -#define _SWAP_FAST_r22 1314 -#define _SWAP_FAST_r33 1315 -#define _SWAP_FAST_0_r01 1316 -#define _SWAP_FAST_0_r11 1317 -#define _SWAP_FAST_0_r22 1318 -#define _SWAP_FAST_0_r33 1319 -#define _SWAP_FAST_1_r01 1320 -#define _SWAP_FAST_1_r11 1321 -#define _SWAP_FAST_1_r22 1322 -#define _SWAP_FAST_1_r33 1323 -#define _SWAP_FAST_2_r01 1324 -#define _SWAP_FAST_2_r11 1325 -#define _SWAP_FAST_2_r22 1326 -#define _SWAP_FAST_2_r33 1327 -#define _SWAP_FAST_3_r01 1328 -#define _SWAP_FAST_3_r11 1329 -#define _SWAP_FAST_3_r22 1330 -#define _SWAP_FAST_3_r33 1331 -#define _SWAP_FAST_4_r01 1332 -#define _SWAP_FAST_4_r11 1333 -#define _SWAP_FAST_4_r22 1334 -#define _SWAP_FAST_4_r33 1335 -#define _SWAP_FAST_5_r01 1336 -#define _SWAP_FAST_5_r11 1337 -#define _SWAP_FAST_5_r22 1338 -#define _SWAP_FAST_5_r33 1339 -#define _SWAP_FAST_6_r01 1340 -#define _SWAP_FAST_6_r11 1341 -#define _SWAP_FAST_6_r22 1342 -#define _SWAP_FAST_6_r33 1343 -#define _SWAP_FAST_7_r01 1344 -#define _SWAP_FAST_7_r11 1345 -#define _SWAP_FAST_7_r22 1346 -#define _SWAP_FAST_7_r33 1347 -#define _TIER2_RESUME_CHECK_r00 1348 -#define _TIER2_RESUME_CHECK_r11 1349 -#define _TIER2_RESUME_CHECK_r22 1350 -#define _TIER2_RESUME_CHECK_r33 1351 -#define _TO_BOOL_r11 1352 -#define _TO_BOOL_BOOL_r01 1353 -#define _TO_BOOL_BOOL_r11 1354 -#define _TO_BOOL_BOOL_r22 1355 -#define _TO_BOOL_BOOL_r33 1356 -#define _TO_BOOL_INT_r02 1357 -#define _TO_BOOL_INT_r12 1358 -#define _TO_BOOL_INT_r23 1359 -#define _TO_BOOL_LIST_r02 1360 -#define _TO_BOOL_LIST_r12 1361 -#define _TO_BOOL_LIST_r23 1362 -#define _TO_BOOL_NONE_r01 1363 -#define _TO_BOOL_NONE_r11 1364 -#define _TO_BOOL_NONE_r22 1365 -#define _TO_BOOL_NONE_r33 1366 -#define _TO_BOOL_STR_r02 1367 -#define _TO_BOOL_STR_r12 1368 -#define _TO_BOOL_STR_r23 1369 -#define _TRACE_RECORD_r00 1370 -#define _UNARY_INVERT_r12 1371 -#define _UNARY_NEGATIVE_r12 1372 -#define _UNARY_NOT_r01 1373 -#define _UNARY_NOT_r11 1374 -#define _UNARY_NOT_r22 1375 -#define _UNARY_NOT_r33 1376 -#define _UNPACK_EX_r10 1377 -#define _UNPACK_SEQUENCE_r10 1378 -#define _UNPACK_SEQUENCE_LIST_r10 1379 -#define _UNPACK_SEQUENCE_TUPLE_r10 1380 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1381 -#define _WITH_EXCEPT_START_r33 1382 -#define _YIELD_VALUE_r11 1383 -#define MAX_UOP_REGS_ID 1383 +#define MAX_UOP_ID 578 +#define _BINARY_OP_r21 579 +#define _BINARY_OP_ADD_FLOAT_r03 580 +#define _BINARY_OP_ADD_FLOAT_r13 581 +#define _BINARY_OP_ADD_FLOAT_r23 582 +#define _BINARY_OP_ADD_INT_r03 583 +#define _BINARY_OP_ADD_INT_r13 584 +#define _BINARY_OP_ADD_INT_r23 585 +#define _BINARY_OP_ADD_UNICODE_r03 586 +#define _BINARY_OP_ADD_UNICODE_r13 587 +#define _BINARY_OP_ADD_UNICODE_r23 588 +#define _BINARY_OP_EXTEND_r21 589 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 590 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 591 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 592 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 593 +#define _BINARY_OP_MULTIPLY_INT_r03 594 +#define _BINARY_OP_MULTIPLY_INT_r13 595 +#define _BINARY_OP_MULTIPLY_INT_r23 596 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 597 +#define _BINARY_OP_SUBSCR_DICT_r23 598 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 599 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 600 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 601 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 602 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 603 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 604 +#define _BINARY_OP_SUBSCR_STR_INT_r23 605 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 606 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 607 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 608 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 609 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 610 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 611 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 612 +#define _BINARY_OP_SUBTRACT_INT_r03 613 +#define _BINARY_OP_SUBTRACT_INT_r13 614 +#define _BINARY_OP_SUBTRACT_INT_r23 615 +#define _BINARY_SLICE_r31 616 +#define _BUILD_INTERPOLATION_r01 617 +#define _BUILD_LIST_r01 618 +#define _BUILD_MAP_r01 619 +#define _BUILD_SET_r01 620 +#define _BUILD_SLICE_r01 621 +#define _BUILD_STRING_r01 622 +#define _BUILD_TEMPLATE_r21 623 +#define _BUILD_TUPLE_r01 624 +#define _CALL_BUILTIN_CLASS_r01 625 +#define _CALL_BUILTIN_FAST_r01 626 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 627 +#define _CALL_BUILTIN_O_r03 628 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 629 +#define _CALL_INTRINSIC_1_r11 630 +#define _CALL_INTRINSIC_2_r21 631 +#define _CALL_ISINSTANCE_r31 632 +#define _CALL_KW_NON_PY_r11 633 +#define _CALL_LEN_r33 634 +#define _CALL_LIST_APPEND_r03 635 +#define _CALL_LIST_APPEND_r13 636 +#define _CALL_LIST_APPEND_r23 637 +#define _CALL_LIST_APPEND_r33 638 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 639 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 640 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 641 +#define _CALL_METHOD_DESCRIPTOR_O_r03 642 +#define _CALL_NON_PY_GENERAL_r01 643 +#define _CALL_STR_1_r32 644 +#define _CALL_TUPLE_1_r32 645 +#define _CALL_TYPE_1_r02 646 +#define _CALL_TYPE_1_r12 647 +#define _CALL_TYPE_1_r22 648 +#define _CALL_TYPE_1_r32 649 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 650 +#define _CHECK_ATTR_CLASS_r01 651 +#define _CHECK_ATTR_CLASS_r11 652 +#define _CHECK_ATTR_CLASS_r22 653 +#define _CHECK_ATTR_CLASS_r33 654 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 655 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 656 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 657 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 658 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 659 +#define _CHECK_EG_MATCH_r22 660 +#define _CHECK_EXC_MATCH_r22 661 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 662 +#define _CHECK_FUNCTION_VERSION_r00 663 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 664 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 665 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 666 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 667 +#define _CHECK_FUNCTION_VERSION_KW_r11 668 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 669 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 670 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 671 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 672 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 673 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 674 +#define _CHECK_IS_PY_CALLABLE_EX_r03 675 +#define _CHECK_IS_PY_CALLABLE_EX_r13 676 +#define _CHECK_IS_PY_CALLABLE_EX_r23 677 +#define _CHECK_IS_PY_CALLABLE_EX_r33 678 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 679 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 680 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 681 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 682 +#define _CHECK_METHOD_VERSION_r00 683 +#define _CHECK_METHOD_VERSION_KW_r11 684 +#define _CHECK_PEP_523_r00 685 +#define _CHECK_PEP_523_r11 686 +#define _CHECK_PEP_523_r22 687 +#define _CHECK_PEP_523_r33 688 +#define _CHECK_PERIODIC_r00 689 +#define _CHECK_PERIODIC_AT_END_r00 690 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 691 +#define _CHECK_RECURSION_REMAINING_r00 692 +#define _CHECK_RECURSION_REMAINING_r11 693 +#define _CHECK_RECURSION_REMAINING_r22 694 +#define _CHECK_RECURSION_REMAINING_r33 695 +#define _CHECK_STACK_SPACE_r00 696 +#define _CHECK_STACK_SPACE_OPERAND_r00 697 +#define _CHECK_STACK_SPACE_OPERAND_r11 698 +#define _CHECK_STACK_SPACE_OPERAND_r22 699 +#define _CHECK_STACK_SPACE_OPERAND_r33 700 +#define _CHECK_VALIDITY_r00 701 +#define _CHECK_VALIDITY_r11 702 +#define _CHECK_VALIDITY_r22 703 +#define _CHECK_VALIDITY_r33 704 +#define _COLD_DYNAMIC_EXIT_r00 705 +#define _COLD_EXIT_r00 706 +#define _COMPARE_OP_r21 707 +#define _COMPARE_OP_FLOAT_r03 708 +#define _COMPARE_OP_FLOAT_r13 709 +#define _COMPARE_OP_FLOAT_r23 710 +#define _COMPARE_OP_INT_r23 711 +#define _COMPARE_OP_STR_r23 712 +#define _CONTAINS_OP_r23 713 +#define _CONTAINS_OP_DICT_r23 714 +#define _CONTAINS_OP_SET_r23 715 +#define _CONVERT_VALUE_r11 716 +#define _COPY_r01 717 +#define _COPY_1_r02 718 +#define _COPY_1_r12 719 +#define _COPY_1_r23 720 +#define _COPY_2_r03 721 +#define _COPY_2_r13 722 +#define _COPY_2_r23 723 +#define _COPY_3_r03 724 +#define _COPY_3_r13 725 +#define _COPY_3_r23 726 +#define _COPY_3_r33 727 +#define _COPY_FREE_VARS_r00 728 +#define _COPY_FREE_VARS_r11 729 +#define _COPY_FREE_VARS_r22 730 +#define _COPY_FREE_VARS_r33 731 +#define _CREATE_INIT_FRAME_r01 732 +#define _DELETE_ATTR_r10 733 +#define _DELETE_DEREF_r00 734 +#define _DELETE_FAST_r00 735 +#define _DELETE_GLOBAL_r00 736 +#define _DELETE_NAME_r00 737 +#define _DELETE_SUBSCR_r20 738 +#define _DEOPT_r00 739 +#define _DEOPT_r10 740 +#define _DEOPT_r20 741 +#define _DEOPT_r30 742 +#define _DICT_MERGE_r10 743 +#define _DICT_UPDATE_r10 744 +#define _DO_CALL_r01 745 +#define _DO_CALL_FUNCTION_EX_r31 746 +#define _DO_CALL_KW_r11 747 +#define _DYNAMIC_EXIT_r00 748 +#define _DYNAMIC_EXIT_r10 749 +#define _DYNAMIC_EXIT_r20 750 +#define _DYNAMIC_EXIT_r30 751 +#define _END_FOR_r10 752 +#define _END_SEND_r21 753 +#define _ERROR_POP_N_r00 754 +#define _EXIT_INIT_CHECK_r10 755 +#define _EXIT_TRACE_r00 756 +#define _EXIT_TRACE_r10 757 +#define _EXIT_TRACE_r20 758 +#define _EXIT_TRACE_r30 759 +#define _EXPAND_METHOD_r00 760 +#define _EXPAND_METHOD_KW_r11 761 +#define _FATAL_ERROR_r00 762 +#define _FATAL_ERROR_r11 763 +#define _FATAL_ERROR_r22 764 +#define _FATAL_ERROR_r33 765 +#define _FORMAT_SIMPLE_r11 766 +#define _FORMAT_WITH_SPEC_r21 767 +#define _FOR_ITER_r23 768 +#define _FOR_ITER_GEN_FRAME_r03 769 +#define _FOR_ITER_GEN_FRAME_r13 770 +#define _FOR_ITER_GEN_FRAME_r23 771 +#define _FOR_ITER_TIER_TWO_r23 772 +#define _GET_AITER_r11 773 +#define _GET_ANEXT_r12 774 +#define _GET_AWAITABLE_r11 775 +#define _GET_ITER_r12 776 +#define _GET_LEN_r12 777 +#define _GET_YIELD_FROM_ITER_r11 778 +#define _GUARD_BINARY_OP_EXTEND_r22 779 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 780 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 781 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 782 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 783 +#define _GUARD_BIT_IS_SET_POP_r00 784 +#define _GUARD_BIT_IS_SET_POP_r10 785 +#define _GUARD_BIT_IS_SET_POP_r21 786 +#define _GUARD_BIT_IS_SET_POP_r32 787 +#define _GUARD_BIT_IS_SET_POP_4_r00 788 +#define _GUARD_BIT_IS_SET_POP_4_r10 789 +#define _GUARD_BIT_IS_SET_POP_4_r21 790 +#define _GUARD_BIT_IS_SET_POP_4_r32 791 +#define _GUARD_BIT_IS_SET_POP_5_r00 792 +#define _GUARD_BIT_IS_SET_POP_5_r10 793 +#define _GUARD_BIT_IS_SET_POP_5_r21 794 +#define _GUARD_BIT_IS_SET_POP_5_r32 795 +#define _GUARD_BIT_IS_SET_POP_6_r00 796 +#define _GUARD_BIT_IS_SET_POP_6_r10 797 +#define _GUARD_BIT_IS_SET_POP_6_r21 798 +#define _GUARD_BIT_IS_SET_POP_6_r32 799 +#define _GUARD_BIT_IS_SET_POP_7_r00 800 +#define _GUARD_BIT_IS_SET_POP_7_r10 801 +#define _GUARD_BIT_IS_SET_POP_7_r21 802 +#define _GUARD_BIT_IS_SET_POP_7_r32 803 +#define _GUARD_BIT_IS_UNSET_POP_r00 804 +#define _GUARD_BIT_IS_UNSET_POP_r10 805 +#define _GUARD_BIT_IS_UNSET_POP_r21 806 +#define _GUARD_BIT_IS_UNSET_POP_r32 807 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 808 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 809 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 810 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 811 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 812 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 813 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 814 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 815 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 816 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 817 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 818 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 819 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 820 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 821 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 822 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 823 +#define _GUARD_CALLABLE_ISINSTANCE_r03 824 +#define _GUARD_CALLABLE_ISINSTANCE_r13 825 +#define _GUARD_CALLABLE_ISINSTANCE_r23 826 +#define _GUARD_CALLABLE_ISINSTANCE_r33 827 +#define _GUARD_CALLABLE_LEN_r03 828 +#define _GUARD_CALLABLE_LEN_r13 829 +#define _GUARD_CALLABLE_LEN_r23 830 +#define _GUARD_CALLABLE_LEN_r33 831 +#define _GUARD_CALLABLE_LIST_APPEND_r03 832 +#define _GUARD_CALLABLE_LIST_APPEND_r13 833 +#define _GUARD_CALLABLE_LIST_APPEND_r23 834 +#define _GUARD_CALLABLE_LIST_APPEND_r33 835 +#define _GUARD_CALLABLE_STR_1_r03 836 +#define _GUARD_CALLABLE_STR_1_r13 837 +#define _GUARD_CALLABLE_STR_1_r23 838 +#define _GUARD_CALLABLE_STR_1_r33 839 +#define _GUARD_CALLABLE_TUPLE_1_r03 840 +#define _GUARD_CALLABLE_TUPLE_1_r13 841 +#define _GUARD_CALLABLE_TUPLE_1_r23 842 +#define _GUARD_CALLABLE_TUPLE_1_r33 843 +#define _GUARD_CALLABLE_TYPE_1_r03 844 +#define _GUARD_CALLABLE_TYPE_1_r13 845 +#define _GUARD_CALLABLE_TYPE_1_r23 846 +#define _GUARD_CALLABLE_TYPE_1_r33 847 +#define _GUARD_DORV_NO_DICT_r01 848 +#define _GUARD_DORV_NO_DICT_r11 849 +#define _GUARD_DORV_NO_DICT_r22 850 +#define _GUARD_DORV_NO_DICT_r33 851 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 852 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 853 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 854 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 855 +#define _GUARD_GLOBALS_VERSION_r00 856 +#define _GUARD_GLOBALS_VERSION_r11 857 +#define _GUARD_GLOBALS_VERSION_r22 858 +#define _GUARD_GLOBALS_VERSION_r33 859 +#define _GUARD_IP_RETURN_GENERATOR_r00 860 +#define _GUARD_IP_RETURN_GENERATOR_r11 861 +#define _GUARD_IP_RETURN_GENERATOR_r22 862 +#define _GUARD_IP_RETURN_GENERATOR_r33 863 +#define _GUARD_IP_RETURN_VALUE_r00 864 +#define _GUARD_IP_RETURN_VALUE_r11 865 +#define _GUARD_IP_RETURN_VALUE_r22 866 +#define _GUARD_IP_RETURN_VALUE_r33 867 +#define _GUARD_IP_YIELD_VALUE_r00 868 +#define _GUARD_IP_YIELD_VALUE_r11 869 +#define _GUARD_IP_YIELD_VALUE_r22 870 +#define _GUARD_IP_YIELD_VALUE_r33 871 +#define _GUARD_IP__PUSH_FRAME_r00 872 +#define _GUARD_IP__PUSH_FRAME_r11 873 +#define _GUARD_IP__PUSH_FRAME_r22 874 +#define _GUARD_IP__PUSH_FRAME_r33 875 +#define _GUARD_IS_FALSE_POP_r00 876 +#define _GUARD_IS_FALSE_POP_r10 877 +#define _GUARD_IS_FALSE_POP_r21 878 +#define _GUARD_IS_FALSE_POP_r32 879 +#define _GUARD_IS_NONE_POP_r00 880 +#define _GUARD_IS_NONE_POP_r10 881 +#define _GUARD_IS_NONE_POP_r21 882 +#define _GUARD_IS_NONE_POP_r32 883 +#define _GUARD_IS_NOT_NONE_POP_r10 884 +#define _GUARD_IS_TRUE_POP_r00 885 +#define _GUARD_IS_TRUE_POP_r10 886 +#define _GUARD_IS_TRUE_POP_r21 887 +#define _GUARD_IS_TRUE_POP_r32 888 +#define _GUARD_KEYS_VERSION_r01 889 +#define _GUARD_KEYS_VERSION_r11 890 +#define _GUARD_KEYS_VERSION_r22 891 +#define _GUARD_KEYS_VERSION_r33 892 +#define _GUARD_NOS_COMPACT_ASCII_r02 893 +#define _GUARD_NOS_COMPACT_ASCII_r12 894 +#define _GUARD_NOS_COMPACT_ASCII_r22 895 +#define _GUARD_NOS_COMPACT_ASCII_r33 896 +#define _GUARD_NOS_DICT_r02 897 +#define _GUARD_NOS_DICT_r12 898 +#define _GUARD_NOS_DICT_r22 899 +#define _GUARD_NOS_DICT_r33 900 +#define _GUARD_NOS_FLOAT_r02 901 +#define _GUARD_NOS_FLOAT_r12 902 +#define _GUARD_NOS_FLOAT_r22 903 +#define _GUARD_NOS_FLOAT_r33 904 +#define _GUARD_NOS_INT_r02 905 +#define _GUARD_NOS_INT_r12 906 +#define _GUARD_NOS_INT_r22 907 +#define _GUARD_NOS_INT_r33 908 +#define _GUARD_NOS_LIST_r02 909 +#define _GUARD_NOS_LIST_r12 910 +#define _GUARD_NOS_LIST_r22 911 +#define _GUARD_NOS_LIST_r33 912 +#define _GUARD_NOS_NOT_NULL_r02 913 +#define _GUARD_NOS_NOT_NULL_r12 914 +#define _GUARD_NOS_NOT_NULL_r22 915 +#define _GUARD_NOS_NOT_NULL_r33 916 +#define _GUARD_NOS_NULL_r02 917 +#define _GUARD_NOS_NULL_r12 918 +#define _GUARD_NOS_NULL_r22 919 +#define _GUARD_NOS_NULL_r33 920 +#define _GUARD_NOS_OVERFLOWED_r02 921 +#define _GUARD_NOS_OVERFLOWED_r12 922 +#define _GUARD_NOS_OVERFLOWED_r22 923 +#define _GUARD_NOS_OVERFLOWED_r33 924 +#define _GUARD_NOS_TUPLE_r02 925 +#define _GUARD_NOS_TUPLE_r12 926 +#define _GUARD_NOS_TUPLE_r22 927 +#define _GUARD_NOS_TUPLE_r33 928 +#define _GUARD_NOS_UNICODE_r02 929 +#define _GUARD_NOS_UNICODE_r12 930 +#define _GUARD_NOS_UNICODE_r22 931 +#define _GUARD_NOS_UNICODE_r33 932 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 933 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 934 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 935 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 936 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 937 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 938 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 939 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 940 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 941 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 942 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 943 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 944 +#define _GUARD_THIRD_NULL_r03 945 +#define _GUARD_THIRD_NULL_r13 946 +#define _GUARD_THIRD_NULL_r23 947 +#define _GUARD_THIRD_NULL_r33 948 +#define _GUARD_TOS_ANY_SET_r01 949 +#define _GUARD_TOS_ANY_SET_r11 950 +#define _GUARD_TOS_ANY_SET_r22 951 +#define _GUARD_TOS_ANY_SET_r33 952 +#define _GUARD_TOS_DICT_r01 953 +#define _GUARD_TOS_DICT_r11 954 +#define _GUARD_TOS_DICT_r22 955 +#define _GUARD_TOS_DICT_r33 956 +#define _GUARD_TOS_FLOAT_r01 957 +#define _GUARD_TOS_FLOAT_r11 958 +#define _GUARD_TOS_FLOAT_r22 959 +#define _GUARD_TOS_FLOAT_r33 960 +#define _GUARD_TOS_INT_r01 961 +#define _GUARD_TOS_INT_r11 962 +#define _GUARD_TOS_INT_r22 963 +#define _GUARD_TOS_INT_r33 964 +#define _GUARD_TOS_LIST_r01 965 +#define _GUARD_TOS_LIST_r11 966 +#define _GUARD_TOS_LIST_r22 967 +#define _GUARD_TOS_LIST_r33 968 +#define _GUARD_TOS_OVERFLOWED_r01 969 +#define _GUARD_TOS_OVERFLOWED_r11 970 +#define _GUARD_TOS_OVERFLOWED_r22 971 +#define _GUARD_TOS_OVERFLOWED_r33 972 +#define _GUARD_TOS_SLICE_r01 973 +#define _GUARD_TOS_SLICE_r11 974 +#define _GUARD_TOS_SLICE_r22 975 +#define _GUARD_TOS_SLICE_r33 976 +#define _GUARD_TOS_TUPLE_r01 977 +#define _GUARD_TOS_TUPLE_r11 978 +#define _GUARD_TOS_TUPLE_r22 979 +#define _GUARD_TOS_TUPLE_r33 980 +#define _GUARD_TOS_UNICODE_r01 981 +#define _GUARD_TOS_UNICODE_r11 982 +#define _GUARD_TOS_UNICODE_r22 983 +#define _GUARD_TOS_UNICODE_r33 984 +#define _GUARD_TYPE_VERSION_r01 985 +#define _GUARD_TYPE_VERSION_r11 986 +#define _GUARD_TYPE_VERSION_r22 987 +#define _GUARD_TYPE_VERSION_r33 988 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 989 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 990 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 991 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 992 +#define _HANDLE_PENDING_AND_DEOPT_r00 993 +#define _HANDLE_PENDING_AND_DEOPT_r10 994 +#define _HANDLE_PENDING_AND_DEOPT_r20 995 +#define _HANDLE_PENDING_AND_DEOPT_r30 996 +#define _IMPORT_FROM_r12 997 +#define _IMPORT_NAME_r21 998 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 999 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1000 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1001 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1002 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1003 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1004 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1005 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1006 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1007 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1008 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1009 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1010 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1011 +#define _INSERT_NULL_r10 1012 +#define _INSTRUMENTED_FOR_ITER_r23 1013 +#define _INSTRUMENTED_INSTRUCTION_r00 1014 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1015 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1016 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1017 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1018 +#define _INSTRUMENTED_LINE_r00 1019 +#define _INSTRUMENTED_NOT_TAKEN_r00 1020 +#define _INSTRUMENTED_NOT_TAKEN_r11 1021 +#define _INSTRUMENTED_NOT_TAKEN_r22 1022 +#define _INSTRUMENTED_NOT_TAKEN_r33 1023 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1024 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1025 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1026 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1027 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1028 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1029 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1030 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1031 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1032 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1033 +#define _IS_NONE_r11 1034 +#define _IS_OP_r03 1035 +#define _IS_OP_r13 1036 +#define _IS_OP_r23 1037 +#define _ITER_CHECK_LIST_r02 1038 +#define _ITER_CHECK_LIST_r12 1039 +#define _ITER_CHECK_LIST_r22 1040 +#define _ITER_CHECK_LIST_r33 1041 +#define _ITER_CHECK_RANGE_r02 1042 +#define _ITER_CHECK_RANGE_r12 1043 +#define _ITER_CHECK_RANGE_r22 1044 +#define _ITER_CHECK_RANGE_r33 1045 +#define _ITER_CHECK_TUPLE_r02 1046 +#define _ITER_CHECK_TUPLE_r12 1047 +#define _ITER_CHECK_TUPLE_r22 1048 +#define _ITER_CHECK_TUPLE_r33 1049 +#define _ITER_JUMP_LIST_r02 1050 +#define _ITER_JUMP_LIST_r12 1051 +#define _ITER_JUMP_LIST_r22 1052 +#define _ITER_JUMP_LIST_r33 1053 +#define _ITER_JUMP_RANGE_r02 1054 +#define _ITER_JUMP_RANGE_r12 1055 +#define _ITER_JUMP_RANGE_r22 1056 +#define _ITER_JUMP_RANGE_r33 1057 +#define _ITER_JUMP_TUPLE_r02 1058 +#define _ITER_JUMP_TUPLE_r12 1059 +#define _ITER_JUMP_TUPLE_r22 1060 +#define _ITER_JUMP_TUPLE_r33 1061 +#define _ITER_NEXT_LIST_r23 1062 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1063 +#define _ITER_NEXT_RANGE_r03 1064 +#define _ITER_NEXT_RANGE_r13 1065 +#define _ITER_NEXT_RANGE_r23 1066 +#define _ITER_NEXT_TUPLE_r03 1067 +#define _ITER_NEXT_TUPLE_r13 1068 +#define _ITER_NEXT_TUPLE_r23 1069 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1070 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1071 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1072 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1073 +#define _JUMP_TO_TOP_r00 1074 +#define _LIST_APPEND_r10 1075 +#define _LIST_EXTEND_r10 1076 +#define _LOAD_ATTR_r10 1077 +#define _LOAD_ATTR_CLASS_r11 1078 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1079 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1080 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1081 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1082 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1083 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1084 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1085 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1086 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1087 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1088 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1089 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1090 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1091 +#define _LOAD_ATTR_MODULE_r11 1092 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1093 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1094 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1095 +#define _LOAD_ATTR_SLOT_r02 1096 +#define _LOAD_ATTR_SLOT_r12 1097 +#define _LOAD_ATTR_SLOT_r23 1098 +#define _LOAD_ATTR_WITH_HINT_r12 1099 +#define _LOAD_BUILD_CLASS_r01 1100 +#define _LOAD_BYTECODE_r00 1101 +#define _LOAD_COMMON_CONSTANT_r01 1102 +#define _LOAD_COMMON_CONSTANT_r12 1103 +#define _LOAD_COMMON_CONSTANT_r23 1104 +#define _LOAD_CONST_r01 1105 +#define _LOAD_CONST_r12 1106 +#define _LOAD_CONST_r23 1107 +#define _LOAD_CONST_INLINE_r01 1108 +#define _LOAD_CONST_INLINE_r12 1109 +#define _LOAD_CONST_INLINE_r23 1110 +#define _LOAD_CONST_INLINE_BORROW_r01 1111 +#define _LOAD_CONST_INLINE_BORROW_r12 1112 +#define _LOAD_CONST_INLINE_BORROW_r23 1113 +#define _LOAD_CONST_UNDER_INLINE_r02 1114 +#define _LOAD_CONST_UNDER_INLINE_r12 1115 +#define _LOAD_CONST_UNDER_INLINE_r23 1116 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1117 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1118 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1119 +#define _LOAD_DEREF_r01 1120 +#define _LOAD_FAST_r01 1121 +#define _LOAD_FAST_r12 1122 +#define _LOAD_FAST_r23 1123 +#define _LOAD_FAST_0_r01 1124 +#define _LOAD_FAST_0_r12 1125 +#define _LOAD_FAST_0_r23 1126 +#define _LOAD_FAST_1_r01 1127 +#define _LOAD_FAST_1_r12 1128 +#define _LOAD_FAST_1_r23 1129 +#define _LOAD_FAST_2_r01 1130 +#define _LOAD_FAST_2_r12 1131 +#define _LOAD_FAST_2_r23 1132 +#define _LOAD_FAST_3_r01 1133 +#define _LOAD_FAST_3_r12 1134 +#define _LOAD_FAST_3_r23 1135 +#define _LOAD_FAST_4_r01 1136 +#define _LOAD_FAST_4_r12 1137 +#define _LOAD_FAST_4_r23 1138 +#define _LOAD_FAST_5_r01 1139 +#define _LOAD_FAST_5_r12 1140 +#define _LOAD_FAST_5_r23 1141 +#define _LOAD_FAST_6_r01 1142 +#define _LOAD_FAST_6_r12 1143 +#define _LOAD_FAST_6_r23 1144 +#define _LOAD_FAST_7_r01 1145 +#define _LOAD_FAST_7_r12 1146 +#define _LOAD_FAST_7_r23 1147 +#define _LOAD_FAST_AND_CLEAR_r01 1148 +#define _LOAD_FAST_AND_CLEAR_r12 1149 +#define _LOAD_FAST_AND_CLEAR_r23 1150 +#define _LOAD_FAST_BORROW_r01 1151 +#define _LOAD_FAST_BORROW_r12 1152 +#define _LOAD_FAST_BORROW_r23 1153 +#define _LOAD_FAST_BORROW_0_r01 1154 +#define _LOAD_FAST_BORROW_0_r12 1155 +#define _LOAD_FAST_BORROW_0_r23 1156 +#define _LOAD_FAST_BORROW_1_r01 1157 +#define _LOAD_FAST_BORROW_1_r12 1158 +#define _LOAD_FAST_BORROW_1_r23 1159 +#define _LOAD_FAST_BORROW_2_r01 1160 +#define _LOAD_FAST_BORROW_2_r12 1161 +#define _LOAD_FAST_BORROW_2_r23 1162 +#define _LOAD_FAST_BORROW_3_r01 1163 +#define _LOAD_FAST_BORROW_3_r12 1164 +#define _LOAD_FAST_BORROW_3_r23 1165 +#define _LOAD_FAST_BORROW_4_r01 1166 +#define _LOAD_FAST_BORROW_4_r12 1167 +#define _LOAD_FAST_BORROW_4_r23 1168 +#define _LOAD_FAST_BORROW_5_r01 1169 +#define _LOAD_FAST_BORROW_5_r12 1170 +#define _LOAD_FAST_BORROW_5_r23 1171 +#define _LOAD_FAST_BORROW_6_r01 1172 +#define _LOAD_FAST_BORROW_6_r12 1173 +#define _LOAD_FAST_BORROW_6_r23 1174 +#define _LOAD_FAST_BORROW_7_r01 1175 +#define _LOAD_FAST_BORROW_7_r12 1176 +#define _LOAD_FAST_BORROW_7_r23 1177 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1178 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1179 +#define _LOAD_FAST_CHECK_r01 1180 +#define _LOAD_FAST_CHECK_r12 1181 +#define _LOAD_FAST_CHECK_r23 1182 +#define _LOAD_FAST_LOAD_FAST_r02 1183 +#define _LOAD_FAST_LOAD_FAST_r13 1184 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1185 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1186 +#define _LOAD_GLOBAL_r00 1187 +#define _LOAD_GLOBAL_BUILTINS_r01 1188 +#define _LOAD_GLOBAL_MODULE_r01 1189 +#define _LOAD_LOCALS_r01 1190 +#define _LOAD_LOCALS_r12 1191 +#define _LOAD_LOCALS_r23 1192 +#define _LOAD_NAME_r01 1193 +#define _LOAD_SMALL_INT_r01 1194 +#define _LOAD_SMALL_INT_r12 1195 +#define _LOAD_SMALL_INT_r23 1196 +#define _LOAD_SMALL_INT_0_r01 1197 +#define _LOAD_SMALL_INT_0_r12 1198 +#define _LOAD_SMALL_INT_0_r23 1199 +#define _LOAD_SMALL_INT_1_r01 1200 +#define _LOAD_SMALL_INT_1_r12 1201 +#define _LOAD_SMALL_INT_1_r23 1202 +#define _LOAD_SMALL_INT_2_r01 1203 +#define _LOAD_SMALL_INT_2_r12 1204 +#define _LOAD_SMALL_INT_2_r23 1205 +#define _LOAD_SMALL_INT_3_r01 1206 +#define _LOAD_SMALL_INT_3_r12 1207 +#define _LOAD_SMALL_INT_3_r23 1208 +#define _LOAD_SPECIAL_r00 1209 +#define _LOAD_SUPER_ATTR_ATTR_r31 1210 +#define _LOAD_SUPER_ATTR_METHOD_r32 1211 +#define _MAKE_CALLARGS_A_TUPLE_r33 1212 +#define _MAKE_CELL_r00 1213 +#define _MAKE_FUNCTION_r11 1214 +#define _MAKE_WARM_r00 1215 +#define _MAKE_WARM_r11 1216 +#define _MAKE_WARM_r22 1217 +#define _MAKE_WARM_r33 1218 +#define _MAP_ADD_r20 1219 +#define _MATCH_CLASS_r31 1220 +#define _MATCH_KEYS_r23 1221 +#define _MATCH_MAPPING_r02 1222 +#define _MATCH_MAPPING_r12 1223 +#define _MATCH_MAPPING_r23 1224 +#define _MATCH_SEQUENCE_r02 1225 +#define _MATCH_SEQUENCE_r12 1226 +#define _MATCH_SEQUENCE_r23 1227 +#define _MAYBE_EXPAND_METHOD_r00 1228 +#define _MAYBE_EXPAND_METHOD_KW_r11 1229 +#define _MONITOR_CALL_r00 1230 +#define _MONITOR_CALL_KW_r11 1231 +#define _MONITOR_JUMP_BACKWARD_r00 1232 +#define _MONITOR_JUMP_BACKWARD_r11 1233 +#define _MONITOR_JUMP_BACKWARD_r22 1234 +#define _MONITOR_JUMP_BACKWARD_r33 1235 +#define _MONITOR_RESUME_r00 1236 +#define _NOP_r00 1237 +#define _NOP_r11 1238 +#define _NOP_r22 1239 +#define _NOP_r33 1240 +#define _POP_CALL_r20 1241 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1242 +#define _POP_CALL_ONE_r30 1243 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1244 +#define _POP_CALL_TWO_r30 1245 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1246 +#define _POP_EXCEPT_r10 1247 +#define _POP_ITER_r20 1248 +#define _POP_JUMP_IF_FALSE_r00 1249 +#define _POP_JUMP_IF_FALSE_r10 1250 +#define _POP_JUMP_IF_FALSE_r21 1251 +#define _POP_JUMP_IF_FALSE_r32 1252 +#define _POP_JUMP_IF_TRUE_r00 1253 +#define _POP_JUMP_IF_TRUE_r10 1254 +#define _POP_JUMP_IF_TRUE_r21 1255 +#define _POP_JUMP_IF_TRUE_r32 1256 +#define _POP_TOP_r10 1257 +#define _POP_TOP_FLOAT_r00 1258 +#define _POP_TOP_FLOAT_r10 1259 +#define _POP_TOP_FLOAT_r21 1260 +#define _POP_TOP_FLOAT_r32 1261 +#define _POP_TOP_INT_r00 1262 +#define _POP_TOP_INT_r10 1263 +#define _POP_TOP_INT_r21 1264 +#define _POP_TOP_INT_r32 1265 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1266 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1267 +#define _POP_TOP_NOP_r00 1268 +#define _POP_TOP_NOP_r10 1269 +#define _POP_TOP_NOP_r21 1270 +#define _POP_TOP_NOP_r32 1271 +#define _POP_TOP_UNICODE_r00 1272 +#define _POP_TOP_UNICODE_r10 1273 +#define _POP_TOP_UNICODE_r21 1274 +#define _POP_TOP_UNICODE_r32 1275 +#define _POP_TWO_r20 1276 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1277 +#define _PUSH_EXC_INFO_r02 1278 +#define _PUSH_EXC_INFO_r12 1279 +#define _PUSH_EXC_INFO_r23 1280 +#define _PUSH_FRAME_r10 1281 +#define _PUSH_NULL_r01 1282 +#define _PUSH_NULL_r12 1283 +#define _PUSH_NULL_r23 1284 +#define _PUSH_NULL_CONDITIONAL_r00 1285 +#define _PY_FRAME_EX_r31 1286 +#define _PY_FRAME_GENERAL_r01 1287 +#define _PY_FRAME_KW_r11 1288 +#define _QUICKEN_RESUME_r00 1289 +#define _QUICKEN_RESUME_r11 1290 +#define _QUICKEN_RESUME_r22 1291 +#define _QUICKEN_RESUME_r33 1292 +#define _REPLACE_WITH_TRUE_r02 1293 +#define _REPLACE_WITH_TRUE_r12 1294 +#define _REPLACE_WITH_TRUE_r23 1295 +#define _RESUME_CHECK_r00 1296 +#define _RESUME_CHECK_r11 1297 +#define _RESUME_CHECK_r22 1298 +#define _RESUME_CHECK_r33 1299 +#define _RETURN_GENERATOR_r01 1300 +#define _RETURN_VALUE_r11 1301 +#define _SAVE_RETURN_OFFSET_r00 1302 +#define _SAVE_RETURN_OFFSET_r11 1303 +#define _SAVE_RETURN_OFFSET_r22 1304 +#define _SAVE_RETURN_OFFSET_r33 1305 +#define _SEND_r22 1306 +#define _SEND_GEN_FRAME_r22 1307 +#define _SETUP_ANNOTATIONS_r00 1308 +#define _SET_ADD_r10 1309 +#define _SET_FUNCTION_ATTRIBUTE_r01 1310 +#define _SET_FUNCTION_ATTRIBUTE_r11 1311 +#define _SET_FUNCTION_ATTRIBUTE_r21 1312 +#define _SET_FUNCTION_ATTRIBUTE_r32 1313 +#define _SET_IP_r00 1314 +#define _SET_IP_r11 1315 +#define _SET_IP_r22 1316 +#define _SET_IP_r33 1317 +#define _SET_UPDATE_r10 1318 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1319 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1320 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1321 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1322 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1323 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1324 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1325 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1326 +#define _SPILL_OR_RELOAD_r01 1327 +#define _SPILL_OR_RELOAD_r02 1328 +#define _SPILL_OR_RELOAD_r03 1329 +#define _SPILL_OR_RELOAD_r10 1330 +#define _SPILL_OR_RELOAD_r12 1331 +#define _SPILL_OR_RELOAD_r13 1332 +#define _SPILL_OR_RELOAD_r20 1333 +#define _SPILL_OR_RELOAD_r21 1334 +#define _SPILL_OR_RELOAD_r23 1335 +#define _SPILL_OR_RELOAD_r30 1336 +#define _SPILL_OR_RELOAD_r31 1337 +#define _SPILL_OR_RELOAD_r32 1338 +#define _START_EXECUTOR_r00 1339 +#define _STORE_ATTR_r20 1340 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1341 +#define _STORE_ATTR_SLOT_r21 1342 +#define _STORE_ATTR_WITH_HINT_r21 1343 +#define _STORE_DEREF_r10 1344 +#define _STORE_FAST_LOAD_FAST_r11 1345 +#define _STORE_FAST_STORE_FAST_r20 1346 +#define _STORE_GLOBAL_r10 1347 +#define _STORE_NAME_r10 1348 +#define _STORE_SLICE_r30 1349 +#define _STORE_SUBSCR_r30 1350 +#define _STORE_SUBSCR_DICT_r31 1351 +#define _STORE_SUBSCR_LIST_INT_r32 1352 +#define _SWAP_r11 1353 +#define _SWAP_2_r02 1354 +#define _SWAP_2_r12 1355 +#define _SWAP_2_r22 1356 +#define _SWAP_2_r33 1357 +#define _SWAP_3_r03 1358 +#define _SWAP_3_r13 1359 +#define _SWAP_3_r23 1360 +#define _SWAP_3_r33 1361 +#define _SWAP_FAST_r01 1362 +#define _SWAP_FAST_r11 1363 +#define _SWAP_FAST_r22 1364 +#define _SWAP_FAST_r33 1365 +#define _SWAP_FAST_0_r01 1366 +#define _SWAP_FAST_0_r11 1367 +#define _SWAP_FAST_0_r22 1368 +#define _SWAP_FAST_0_r33 1369 +#define _SWAP_FAST_1_r01 1370 +#define _SWAP_FAST_1_r11 1371 +#define _SWAP_FAST_1_r22 1372 +#define _SWAP_FAST_1_r33 1373 +#define _SWAP_FAST_2_r01 1374 +#define _SWAP_FAST_2_r11 1375 +#define _SWAP_FAST_2_r22 1376 +#define _SWAP_FAST_2_r33 1377 +#define _SWAP_FAST_3_r01 1378 +#define _SWAP_FAST_3_r11 1379 +#define _SWAP_FAST_3_r22 1380 +#define _SWAP_FAST_3_r33 1381 +#define _SWAP_FAST_4_r01 1382 +#define _SWAP_FAST_4_r11 1383 +#define _SWAP_FAST_4_r22 1384 +#define _SWAP_FAST_4_r33 1385 +#define _SWAP_FAST_5_r01 1386 +#define _SWAP_FAST_5_r11 1387 +#define _SWAP_FAST_5_r22 1388 +#define _SWAP_FAST_5_r33 1389 +#define _SWAP_FAST_6_r01 1390 +#define _SWAP_FAST_6_r11 1391 +#define _SWAP_FAST_6_r22 1392 +#define _SWAP_FAST_6_r33 1393 +#define _SWAP_FAST_7_r01 1394 +#define _SWAP_FAST_7_r11 1395 +#define _SWAP_FAST_7_r22 1396 +#define _SWAP_FAST_7_r33 1397 +#define _TIER2_RESUME_CHECK_r00 1398 +#define _TIER2_RESUME_CHECK_r11 1399 +#define _TIER2_RESUME_CHECK_r22 1400 +#define _TIER2_RESUME_CHECK_r33 1401 +#define _TO_BOOL_r11 1402 +#define _TO_BOOL_BOOL_r01 1403 +#define _TO_BOOL_BOOL_r11 1404 +#define _TO_BOOL_BOOL_r22 1405 +#define _TO_BOOL_BOOL_r33 1406 +#define _TO_BOOL_INT_r02 1407 +#define _TO_BOOL_INT_r12 1408 +#define _TO_BOOL_INT_r23 1409 +#define _TO_BOOL_LIST_r02 1410 +#define _TO_BOOL_LIST_r12 1411 +#define _TO_BOOL_LIST_r23 1412 +#define _TO_BOOL_NONE_r01 1413 +#define _TO_BOOL_NONE_r11 1414 +#define _TO_BOOL_NONE_r22 1415 +#define _TO_BOOL_NONE_r33 1416 +#define _TO_BOOL_STR_r02 1417 +#define _TO_BOOL_STR_r12 1418 +#define _TO_BOOL_STR_r23 1419 +#define _TRACE_RECORD_r00 1420 +#define _UNARY_INVERT_r12 1421 +#define _UNARY_NEGATIVE_r12 1422 +#define _UNARY_NOT_r01 1423 +#define _UNARY_NOT_r11 1424 +#define _UNARY_NOT_r22 1425 +#define _UNARY_NOT_r33 1426 +#define _UNPACK_EX_r10 1427 +#define _UNPACK_SEQUENCE_r10 1428 +#define _UNPACK_SEQUENCE_LIST_r10 1429 +#define _UNPACK_SEQUENCE_TUPLE_r10 1430 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1431 +#define _WITH_EXCEPT_START_r33 1432 +#define _YIELD_VALUE_r11 1433 +#define MAX_UOP_REGS_ID 1433 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 6398448d5fa..c2e0f4a2c39 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -323,6 +323,16 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG, [_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_SET_POP_4] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_SET_POP_5] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_SET_POP_6] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_SET_POP_7] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_SET_POP] = HAS_ARG_FLAG | HAS_EXIT_FLAG, + [_GUARD_BIT_IS_UNSET_POP_4] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_UNSET_POP_5] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_UNSET_POP_6] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_UNSET_POP_7] = HAS_EXIT_FLAG, + [_GUARD_BIT_IS_UNSET_POP] = HAS_ARG_FLAG | HAS_EXIT_FLAG, [_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG, [_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG, [_JUMP_TO_TOP] = 0, @@ -373,6 +383,8 @@ const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = { [_INIT_CALL_PY_EXACT_ARGS] = { 0, 5 }, [_COPY] = { 1, 4 }, [_SWAP] = { 2, 4 }, + [_GUARD_BIT_IS_SET_POP] = { 4, 8 }, + [_GUARD_BIT_IS_UNSET_POP] = { 4, 8 }, }; const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { @@ -2968,6 +2980,96 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { 2, 2, _GUARD_IS_FALSE_POP_r32 }, }, }, + [_GUARD_BIT_IS_SET_POP_4] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_SET_POP_4_r00 }, + { 0, 0, _GUARD_BIT_IS_SET_POP_4_r10 }, + { 1, 1, _GUARD_BIT_IS_SET_POP_4_r21 }, + { 2, 2, _GUARD_BIT_IS_SET_POP_4_r32 }, + }, + }, + [_GUARD_BIT_IS_SET_POP_5] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_SET_POP_5_r00 }, + { 0, 0, _GUARD_BIT_IS_SET_POP_5_r10 }, + { 1, 1, _GUARD_BIT_IS_SET_POP_5_r21 }, + { 2, 2, _GUARD_BIT_IS_SET_POP_5_r32 }, + }, + }, + [_GUARD_BIT_IS_SET_POP_6] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_SET_POP_6_r00 }, + { 0, 0, _GUARD_BIT_IS_SET_POP_6_r10 }, + { 1, 1, _GUARD_BIT_IS_SET_POP_6_r21 }, + { 2, 2, _GUARD_BIT_IS_SET_POP_6_r32 }, + }, + }, + [_GUARD_BIT_IS_SET_POP_7] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_SET_POP_7_r00 }, + { 0, 0, _GUARD_BIT_IS_SET_POP_7_r10 }, + { 1, 1, _GUARD_BIT_IS_SET_POP_7_r21 }, + { 2, 2, _GUARD_BIT_IS_SET_POP_7_r32 }, + }, + }, + [_GUARD_BIT_IS_SET_POP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_SET_POP_r00 }, + { 0, 0, _GUARD_BIT_IS_SET_POP_r10 }, + { 1, 1, _GUARD_BIT_IS_SET_POP_r21 }, + { 2, 2, _GUARD_BIT_IS_SET_POP_r32 }, + }, + }, + [_GUARD_BIT_IS_UNSET_POP_4] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_UNSET_POP_4_r00 }, + { 0, 0, _GUARD_BIT_IS_UNSET_POP_4_r10 }, + { 1, 1, _GUARD_BIT_IS_UNSET_POP_4_r21 }, + { 2, 2, _GUARD_BIT_IS_UNSET_POP_4_r32 }, + }, + }, + [_GUARD_BIT_IS_UNSET_POP_5] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_UNSET_POP_5_r00 }, + { 0, 0, _GUARD_BIT_IS_UNSET_POP_5_r10 }, + { 1, 1, _GUARD_BIT_IS_UNSET_POP_5_r21 }, + { 2, 2, _GUARD_BIT_IS_UNSET_POP_5_r32 }, + }, + }, + [_GUARD_BIT_IS_UNSET_POP_6] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_UNSET_POP_6_r00 }, + { 0, 0, _GUARD_BIT_IS_UNSET_POP_6_r10 }, + { 1, 1, _GUARD_BIT_IS_UNSET_POP_6_r21 }, + { 2, 2, _GUARD_BIT_IS_UNSET_POP_6_r32 }, + }, + }, + [_GUARD_BIT_IS_UNSET_POP_7] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_UNSET_POP_7_r00 }, + { 0, 0, _GUARD_BIT_IS_UNSET_POP_7_r10 }, + { 1, 1, _GUARD_BIT_IS_UNSET_POP_7_r21 }, + { 2, 2, _GUARD_BIT_IS_UNSET_POP_7_r32 }, + }, + }, + [_GUARD_BIT_IS_UNSET_POP] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 0, 0, _GUARD_BIT_IS_UNSET_POP_r00 }, + { 0, 0, _GUARD_BIT_IS_UNSET_POP_r10 }, + { 1, 1, _GUARD_BIT_IS_UNSET_POP_r21 }, + { 2, 2, _GUARD_BIT_IS_UNSET_POP_r32 }, + }, + }, [_GUARD_IS_NONE_POP] = { .best = { 0, 1, 2, 3 }, .entries = { @@ -3947,6 +4049,46 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_GUARD_IS_FALSE_POP_r10] = _GUARD_IS_FALSE_POP, [_GUARD_IS_FALSE_POP_r21] = _GUARD_IS_FALSE_POP, [_GUARD_IS_FALSE_POP_r32] = _GUARD_IS_FALSE_POP, + [_GUARD_BIT_IS_SET_POP_4_r00] = _GUARD_BIT_IS_SET_POP_4, + [_GUARD_BIT_IS_SET_POP_4_r10] = _GUARD_BIT_IS_SET_POP_4, + [_GUARD_BIT_IS_SET_POP_4_r21] = _GUARD_BIT_IS_SET_POP_4, + [_GUARD_BIT_IS_SET_POP_4_r32] = _GUARD_BIT_IS_SET_POP_4, + [_GUARD_BIT_IS_SET_POP_5_r00] = _GUARD_BIT_IS_SET_POP_5, + [_GUARD_BIT_IS_SET_POP_5_r10] = _GUARD_BIT_IS_SET_POP_5, + [_GUARD_BIT_IS_SET_POP_5_r21] = _GUARD_BIT_IS_SET_POP_5, + [_GUARD_BIT_IS_SET_POP_5_r32] = _GUARD_BIT_IS_SET_POP_5, + [_GUARD_BIT_IS_SET_POP_6_r00] = _GUARD_BIT_IS_SET_POP_6, + [_GUARD_BIT_IS_SET_POP_6_r10] = _GUARD_BIT_IS_SET_POP_6, + [_GUARD_BIT_IS_SET_POP_6_r21] = _GUARD_BIT_IS_SET_POP_6, + [_GUARD_BIT_IS_SET_POP_6_r32] = _GUARD_BIT_IS_SET_POP_6, + [_GUARD_BIT_IS_SET_POP_7_r00] = _GUARD_BIT_IS_SET_POP_7, + [_GUARD_BIT_IS_SET_POP_7_r10] = _GUARD_BIT_IS_SET_POP_7, + [_GUARD_BIT_IS_SET_POP_7_r21] = _GUARD_BIT_IS_SET_POP_7, + [_GUARD_BIT_IS_SET_POP_7_r32] = _GUARD_BIT_IS_SET_POP_7, + [_GUARD_BIT_IS_SET_POP_r00] = _GUARD_BIT_IS_SET_POP, + [_GUARD_BIT_IS_SET_POP_r10] = _GUARD_BIT_IS_SET_POP, + [_GUARD_BIT_IS_SET_POP_r21] = _GUARD_BIT_IS_SET_POP, + [_GUARD_BIT_IS_SET_POP_r32] = _GUARD_BIT_IS_SET_POP, + [_GUARD_BIT_IS_UNSET_POP_4_r00] = _GUARD_BIT_IS_UNSET_POP_4, + [_GUARD_BIT_IS_UNSET_POP_4_r10] = _GUARD_BIT_IS_UNSET_POP_4, + [_GUARD_BIT_IS_UNSET_POP_4_r21] = _GUARD_BIT_IS_UNSET_POP_4, + [_GUARD_BIT_IS_UNSET_POP_4_r32] = _GUARD_BIT_IS_UNSET_POP_4, + [_GUARD_BIT_IS_UNSET_POP_5_r00] = _GUARD_BIT_IS_UNSET_POP_5, + [_GUARD_BIT_IS_UNSET_POP_5_r10] = _GUARD_BIT_IS_UNSET_POP_5, + [_GUARD_BIT_IS_UNSET_POP_5_r21] = _GUARD_BIT_IS_UNSET_POP_5, + [_GUARD_BIT_IS_UNSET_POP_5_r32] = _GUARD_BIT_IS_UNSET_POP_5, + [_GUARD_BIT_IS_UNSET_POP_6_r00] = _GUARD_BIT_IS_UNSET_POP_6, + [_GUARD_BIT_IS_UNSET_POP_6_r10] = _GUARD_BIT_IS_UNSET_POP_6, + [_GUARD_BIT_IS_UNSET_POP_6_r21] = _GUARD_BIT_IS_UNSET_POP_6, + [_GUARD_BIT_IS_UNSET_POP_6_r32] = _GUARD_BIT_IS_UNSET_POP_6, + [_GUARD_BIT_IS_UNSET_POP_7_r00] = _GUARD_BIT_IS_UNSET_POP_7, + [_GUARD_BIT_IS_UNSET_POP_7_r10] = _GUARD_BIT_IS_UNSET_POP_7, + [_GUARD_BIT_IS_UNSET_POP_7_r21] = _GUARD_BIT_IS_UNSET_POP_7, + [_GUARD_BIT_IS_UNSET_POP_7_r32] = _GUARD_BIT_IS_UNSET_POP_7, + [_GUARD_BIT_IS_UNSET_POP_r00] = _GUARD_BIT_IS_UNSET_POP, + [_GUARD_BIT_IS_UNSET_POP_r10] = _GUARD_BIT_IS_UNSET_POP, + [_GUARD_BIT_IS_UNSET_POP_r21] = _GUARD_BIT_IS_UNSET_POP, + [_GUARD_BIT_IS_UNSET_POP_r32] = _GUARD_BIT_IS_UNSET_POP, [_GUARD_IS_NONE_POP_r00] = _GUARD_IS_NONE_POP, [_GUARD_IS_NONE_POP_r10] = _GUARD_IS_NONE_POP, [_GUARD_IS_NONE_POP_r21] = _GUARD_IS_NONE_POP, @@ -4398,6 +4540,56 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12", [_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22", [_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33", + [_GUARD_BIT_IS_SET_POP] = "_GUARD_BIT_IS_SET_POP", + [_GUARD_BIT_IS_SET_POP_r00] = "_GUARD_BIT_IS_SET_POP_r00", + [_GUARD_BIT_IS_SET_POP_r10] = "_GUARD_BIT_IS_SET_POP_r10", + [_GUARD_BIT_IS_SET_POP_r21] = "_GUARD_BIT_IS_SET_POP_r21", + [_GUARD_BIT_IS_SET_POP_r32] = "_GUARD_BIT_IS_SET_POP_r32", + [_GUARD_BIT_IS_SET_POP_4] = "_GUARD_BIT_IS_SET_POP_4", + [_GUARD_BIT_IS_SET_POP_4_r00] = "_GUARD_BIT_IS_SET_POP_4_r00", + [_GUARD_BIT_IS_SET_POP_4_r10] = "_GUARD_BIT_IS_SET_POP_4_r10", + [_GUARD_BIT_IS_SET_POP_4_r21] = "_GUARD_BIT_IS_SET_POP_4_r21", + [_GUARD_BIT_IS_SET_POP_4_r32] = "_GUARD_BIT_IS_SET_POP_4_r32", + [_GUARD_BIT_IS_SET_POP_5] = "_GUARD_BIT_IS_SET_POP_5", + [_GUARD_BIT_IS_SET_POP_5_r00] = "_GUARD_BIT_IS_SET_POP_5_r00", + [_GUARD_BIT_IS_SET_POP_5_r10] = "_GUARD_BIT_IS_SET_POP_5_r10", + [_GUARD_BIT_IS_SET_POP_5_r21] = "_GUARD_BIT_IS_SET_POP_5_r21", + [_GUARD_BIT_IS_SET_POP_5_r32] = "_GUARD_BIT_IS_SET_POP_5_r32", + [_GUARD_BIT_IS_SET_POP_6] = "_GUARD_BIT_IS_SET_POP_6", + [_GUARD_BIT_IS_SET_POP_6_r00] = "_GUARD_BIT_IS_SET_POP_6_r00", + [_GUARD_BIT_IS_SET_POP_6_r10] = "_GUARD_BIT_IS_SET_POP_6_r10", + [_GUARD_BIT_IS_SET_POP_6_r21] = "_GUARD_BIT_IS_SET_POP_6_r21", + [_GUARD_BIT_IS_SET_POP_6_r32] = "_GUARD_BIT_IS_SET_POP_6_r32", + [_GUARD_BIT_IS_SET_POP_7] = "_GUARD_BIT_IS_SET_POP_7", + [_GUARD_BIT_IS_SET_POP_7_r00] = "_GUARD_BIT_IS_SET_POP_7_r00", + [_GUARD_BIT_IS_SET_POP_7_r10] = "_GUARD_BIT_IS_SET_POP_7_r10", + [_GUARD_BIT_IS_SET_POP_7_r21] = "_GUARD_BIT_IS_SET_POP_7_r21", + [_GUARD_BIT_IS_SET_POP_7_r32] = "_GUARD_BIT_IS_SET_POP_7_r32", + [_GUARD_BIT_IS_UNSET_POP] = "_GUARD_BIT_IS_UNSET_POP", + [_GUARD_BIT_IS_UNSET_POP_r00] = "_GUARD_BIT_IS_UNSET_POP_r00", + [_GUARD_BIT_IS_UNSET_POP_r10] = "_GUARD_BIT_IS_UNSET_POP_r10", + [_GUARD_BIT_IS_UNSET_POP_r21] = "_GUARD_BIT_IS_UNSET_POP_r21", + [_GUARD_BIT_IS_UNSET_POP_r32] = "_GUARD_BIT_IS_UNSET_POP_r32", + [_GUARD_BIT_IS_UNSET_POP_4] = "_GUARD_BIT_IS_UNSET_POP_4", + [_GUARD_BIT_IS_UNSET_POP_4_r00] = "_GUARD_BIT_IS_UNSET_POP_4_r00", + [_GUARD_BIT_IS_UNSET_POP_4_r10] = "_GUARD_BIT_IS_UNSET_POP_4_r10", + [_GUARD_BIT_IS_UNSET_POP_4_r21] = "_GUARD_BIT_IS_UNSET_POP_4_r21", + [_GUARD_BIT_IS_UNSET_POP_4_r32] = "_GUARD_BIT_IS_UNSET_POP_4_r32", + [_GUARD_BIT_IS_UNSET_POP_5] = "_GUARD_BIT_IS_UNSET_POP_5", + [_GUARD_BIT_IS_UNSET_POP_5_r00] = "_GUARD_BIT_IS_UNSET_POP_5_r00", + [_GUARD_BIT_IS_UNSET_POP_5_r10] = "_GUARD_BIT_IS_UNSET_POP_5_r10", + [_GUARD_BIT_IS_UNSET_POP_5_r21] = "_GUARD_BIT_IS_UNSET_POP_5_r21", + [_GUARD_BIT_IS_UNSET_POP_5_r32] = "_GUARD_BIT_IS_UNSET_POP_5_r32", + [_GUARD_BIT_IS_UNSET_POP_6] = "_GUARD_BIT_IS_UNSET_POP_6", + [_GUARD_BIT_IS_UNSET_POP_6_r00] = "_GUARD_BIT_IS_UNSET_POP_6_r00", + [_GUARD_BIT_IS_UNSET_POP_6_r10] = "_GUARD_BIT_IS_UNSET_POP_6_r10", + [_GUARD_BIT_IS_UNSET_POP_6_r21] = "_GUARD_BIT_IS_UNSET_POP_6_r21", + [_GUARD_BIT_IS_UNSET_POP_6_r32] = "_GUARD_BIT_IS_UNSET_POP_6_r32", + [_GUARD_BIT_IS_UNSET_POP_7] = "_GUARD_BIT_IS_UNSET_POP_7", + [_GUARD_BIT_IS_UNSET_POP_7_r00] = "_GUARD_BIT_IS_UNSET_POP_7_r00", + [_GUARD_BIT_IS_UNSET_POP_7_r10] = "_GUARD_BIT_IS_UNSET_POP_7_r10", + [_GUARD_BIT_IS_UNSET_POP_7_r21] = "_GUARD_BIT_IS_UNSET_POP_7_r21", + [_GUARD_BIT_IS_UNSET_POP_7_r32] = "_GUARD_BIT_IS_UNSET_POP_7_r32", [_GUARD_CALLABLE_ISINSTANCE] = "_GUARD_CALLABLE_ISINSTANCE", [_GUARD_CALLABLE_ISINSTANCE_r03] = "_GUARD_CALLABLE_ISINSTANCE_r03", [_GUARD_CALLABLE_ISINSTANCE_r13] = "_GUARD_CALLABLE_ISINSTANCE_r13", @@ -5732,6 +5924,26 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _GUARD_IS_FALSE_POP: return 1; + case _GUARD_BIT_IS_SET_POP_4: + return 1; + case _GUARD_BIT_IS_SET_POP_5: + return 1; + case _GUARD_BIT_IS_SET_POP_6: + return 1; + case _GUARD_BIT_IS_SET_POP_7: + return 1; + case _GUARD_BIT_IS_SET_POP: + return 1; + case _GUARD_BIT_IS_UNSET_POP_4: + return 1; + case _GUARD_BIT_IS_UNSET_POP_5: + return 1; + case _GUARD_BIT_IS_UNSET_POP_6: + return 1; + case _GUARD_BIT_IS_UNSET_POP_7: + return 1; + case _GUARD_BIT_IS_UNSET_POP: + return 1; case _GUARD_IS_NONE_POP: return 1; case _GUARD_IS_NOT_NONE_POP: diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 79c7f530b8a..307eac6ee51 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -153,12 +153,26 @@ def f(start, end, way): f(1, TIER2_THRESHOLD + 1, 1.0) +def get_bool_guard_ops(): + delta = id(True) ^ id(False) + for bit in range(4, 8): + if delta & (1 << bit): + if id(True) & (1 << bit): + return f"_GUARD_BIT_IS_UNSET_POP_{bit}", f"_GUARD_BIT_IS_SET_POP_{bit}" + else: + return f"_GUARD_BIT_IS_SET_POP_{bit}", f"_GUARD_BIT_IS_UNSET_POP_{bit}" + return "_GUARD_IS_FALSE_POP", "_GUARD_IS_TRUE_POP" + + @requires_specialization @unittest.skipIf(Py_GIL_DISABLED, "optimizer not yet supported in free-threaded builds") @requires_jit_enabled @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUops(unittest.TestCase): + def setUp(self): + self.guard_is_false, self.guard_is_true = get_bool_guard_ops() + def test_basic_loop(self): def testfunc(x): i = 0 @@ -250,7 +264,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_GUARD_IS_TRUE_POP", uops) + self.assertIn(self.guard_is_true, uops) def test_pop_jump_if_none(self): def testfunc(a): @@ -292,7 +306,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_GUARD_IS_FALSE_POP", uops) + self.assertIn(self.guard_is_false, uops) def test_jump_backward(self): def testfunc(n): @@ -444,7 +458,7 @@ def testfunc(n): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_GUARD_IS_FALSE_POP", uops) + self.assertIn(self.guard_is_false, uops) def test_for_iter_tier_two(self): class MyIter: @@ -481,6 +495,9 @@ def testfunc(n, m): @unittest.skipIf(os.getenv("PYTHON_UOPS_OPTIMIZE") == "0", "Needs uop optimizer to run.") class TestUopsOptimization(unittest.TestCase): + def setUp(self): + self.guard_is_false, self.guard_is_true = get_bool_guard_ops() + def _run_with_optimizer(self, testfunc, arg): res = testfunc(arg) @@ -1501,8 +1518,8 @@ def f(n): self.assertIsNotNone(ex) uops = get_opnames(ex) # Only one guard remains: - self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 1) - self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 0) + self.assertEqual(uops.count(self.guard_is_false), 1) + self.assertEqual(uops.count(self.guard_is_true), 0) # But all of the appends we care about are still there: self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG")) @@ -1532,8 +1549,8 @@ def f(n): self.assertIsNotNone(ex) uops = get_opnames(ex) # Only one guard remains: - self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 0) - self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 1) + self.assertEqual(uops.count(self.guard_is_false), 0) + self.assertEqual(uops.count(self.guard_is_true), 1) # But all of the appends we care about are still there: self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG")) @@ -1564,8 +1581,8 @@ def f(n): self.assertIsNotNone(ex) uops = get_opnames(ex) # Only one guard remains: - self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 1) - self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 0) + self.assertEqual(uops.count(self.guard_is_false), 1) + self.assertEqual(uops.count(self.guard_is_true), 0) # But all of the appends we care about are still there: self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG")) @@ -1597,8 +1614,8 @@ def f(n): self.assertIsNotNone(ex) uops = get_opnames(ex) # Only one guard remains: - self.assertEqual(uops.count("_GUARD_IS_FALSE_POP"), 1) - self.assertEqual(uops.count("_GUARD_IS_TRUE_POP"), 0) + self.assertEqual(uops.count(self.guard_is_false), 1) + self.assertEqual(uops.count(self.guard_is_true), 0) # But all of the appends we care about are still there: self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG")) @@ -2196,7 +2213,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_CALL_STR_1", uops) self.assertNotIn("_TO_BOOL_STR", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) def test_call_tuple_1(self): def testfunc(n): @@ -2253,7 +2270,7 @@ def testfunc(n): self.assertIn("_CALL_TUPLE_1", uops) self.assertIn("_UNPACK_SEQUENCE_TWO_TUPLE", uops) self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) def test_call_len(self): def testfunc(n): @@ -2319,7 +2336,7 @@ class C: # in this case self.assertIn("_CALL_LEN", uops) self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) def test_call_builtin_o(self): def testfunc(n): @@ -2413,7 +2430,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_BINARY_OP_SUBSCR_TUPLE_INT", uops) self.assertNotIn("_COMPARE_OP_INT", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) def test_call_isinstance_guards_removed(self): def testfunc(n): @@ -2478,7 +2495,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertNotIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops) @@ -2499,7 +2516,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertNotIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertNotIn("_GUARD_IS_FALSE_POP", uops) + self.assertNotIn(self.guard_is_false, uops) self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops) @@ -2520,7 +2537,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertNotIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + self.assertNotIn(self.guard_is_true, uops) self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_LOAD_CONST_INLINE_BORROW", uops) self.assertNotIn("_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW", uops) @@ -2544,7 +2561,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertIn("_GUARD_IS_TRUE_POP", uops) + self.assertIn(self.guard_is_true, uops) def test_call_isinstance_tuple_of_classes(self): def testfunc(n): @@ -2563,7 +2580,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertIn("_GUARD_IS_TRUE_POP", uops) + self.assertIn(self.guard_is_true, uops) def test_call_isinstance_metaclass(self): class EvenNumberMeta(type): @@ -2588,7 +2605,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_CALL_ISINSTANCE", uops) self.assertNotIn("_TO_BOOL_BOOL", uops) - self.assertIn("_GUARD_IS_TRUE_POP", uops) + self.assertIn(self.guard_is_true, uops) def test_set_type_version_sets_type(self): class C: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 5f2461df8e6..cef368e9b07 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5273,6 +5273,28 @@ dummy_func( AT_END_EXIT_IF(!is_false); } + replicate(4:8) op (_GUARD_BIT_IS_SET_POP, (flag -- )) { +#ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; +#else + uintptr_t bits = flag.bits; +#endif + uintptr_t set = (1 << oparg) & bits; + DEAD(flag); + AT_END_EXIT_IF(set == 0); + } + + replicate(4:8) op (_GUARD_BIT_IS_UNSET_POP, (flag -- )) { +#ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; +#else + uintptr_t bits = flag.bits; +#endif + uintptr_t set = (1 << oparg) & bits; + DEAD(flag); + AT_END_EXIT_IF(set != 0); + } + op (_GUARD_IS_NONE_POP, (val -- )) { int is_none = PyStackRef_IsNone(val); if (!is_none) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 8f9b62b0bab..4d4084971c7 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -17006,6 +17006,1078 @@ break; } + case _GUARD_BIT_IS_SET_POP_4_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_4_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_4_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_4_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_5_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_5_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_5_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_5_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_6_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_6_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_6_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_6_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_7_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_7_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_7_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_7_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = CURRENT_OPARG(); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_SET_POP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set == 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_4_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_4_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_4_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_4_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 4; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_5_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_5_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_5_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_5_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 5; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_6_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_6_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_6_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_6_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 6; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_7_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_7_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_7_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_7_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = 7; + assert(oparg == CURRENT_OPARG()); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_r00: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + oparg = CURRENT_OPARG(); + flag = stack_pointer[-1]; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_r10: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + oparg = CURRENT_OPARG(); + flag = _stack_item_0; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + SET_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + oparg = CURRENT_OPARG(); + flag = _stack_item_1; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_BIT_IS_UNSET_POP_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef flag; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + oparg = CURRENT_OPARG(); + flag = _stack_item_2; + #ifdef Py_STACKREF_DEBUG + uintptr_t bits = flag.index; + #else + uintptr_t bits = flag.bits; + #endif + uintptr_t set = (1 << oparg) & bits; + if (set != 0) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _GUARD_IS_NONE_POP_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index d635ebabf90..01fd24564f8 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -363,6 +363,34 @@ get_co_name(JitOptContext *ctx, int index) return PyTuple_GET_ITEM(get_current_code_object(ctx)->co_names, index); } +static int +get_test_bit_for_bools(void) { +#ifdef Py_STACKREF_DEBUG + uintptr_t false_bits = _Py_STACKREF_FALSE_INDEX; + uintptr_t true_bits = _Py_STACKREF_TRUE_INDEX; +#else + uintptr_t false_bits = (uintptr_t)&_Py_FalseStruct; + uintptr_t true_bits = (uintptr_t)&_Py_TrueStruct; +#endif + for (int i = 4; i < 8; i++) { + if ((true_bits ^ false_bits) & (1 << i)) { + return i; + } + } + return 0; +} + +static int +test_bit_set_in_true(int bit) { +#ifdef Py_STACKREF_DEBUG + uintptr_t true_bits = _Py_STACKREF_TRUE_INDEX; +#else + uintptr_t true_bits = (uintptr_t)&_Py_TrueStruct; +#endif + assert((true_bits ^ ((uintptr_t)&_Py_FalseStruct)) & (1 << bit)); + return true_bits & (1 << bit); +} + #ifdef Py_DEBUG void _Py_opt_assert_within_stack_bounds( diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 876ba7c6de7..366094d939a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1136,15 +1136,6 @@ dummy_func(void) { } } - op(_GUARD_IS_TRUE_POP, (flag -- )) { - if (sym_is_const(ctx, flag)) { - PyObject *value = sym_get_const(ctx, flag); - assert(value != NULL); - eliminate_pop_guard(this_instr, ctx, value != Py_True); - } - sym_set_const(flag, Py_True); - } - op(_CALL_LIST_APPEND, (callable, self, arg -- none, c, s)) { (void)(arg); c = callable; @@ -1181,12 +1172,39 @@ dummy_func(void) { } } + op(_GUARD_IS_TRUE_POP, (flag -- )) { + if (sym_is_const(ctx, flag)) { + PyObject *value = sym_get_const(ctx, flag); + assert(value != NULL); + eliminate_pop_guard(this_instr, ctx, value != Py_True); + } + else { + int bit = get_test_bit_for_bools(); + if (bit) { + REPLACE_OP(this_instr, + test_bit_set_in_true(bit) ? + _GUARD_BIT_IS_SET_POP : + _GUARD_BIT_IS_UNSET_POP, bit, 0); + } + } + sym_set_const(flag, Py_True); + } + op(_GUARD_IS_FALSE_POP, (flag -- )) { if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); assert(value != NULL); eliminate_pop_guard(this_instr, ctx, value != Py_False); } + else { + int bit = get_test_bit_for_bools(); + if (bit) { + REPLACE_OP(this_instr, + test_bit_set_in_true(bit) ? + _GUARD_BIT_IS_UNSET_POP : + _GUARD_BIT_IS_SET_POP, bit, 0); + } + } sym_set_const(flag, Py_False); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 012fe16bfd9..2cc53937925 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3720,6 +3720,15 @@ assert(value != NULL); eliminate_pop_guard(this_instr, ctx, value != Py_True); } + else { + int bit = get_test_bit_for_bools(); + if (bit) { + REPLACE_OP(this_instr, + test_bit_set_in_true(bit) ? + _GUARD_BIT_IS_SET_POP : + _GUARD_BIT_IS_UNSET_POP, bit, 0); + } + } sym_set_const(flag, Py_True); CHECK_STACK_BOUNDS(-1); stack_pointer += -1; @@ -3735,6 +3744,15 @@ assert(value != NULL); eliminate_pop_guard(this_instr, ctx, value != Py_False); } + else { + int bit = get_test_bit_for_bools(); + if (bit) { + REPLACE_OP(this_instr, + test_bit_set_in_true(bit) ? + _GUARD_BIT_IS_UNSET_POP : + _GUARD_BIT_IS_SET_POP, bit, 0); + } + } sym_set_const(flag, Py_False); CHECK_STACK_BOUNDS(-1); stack_pointer += -1; @@ -3742,6 +3760,20 @@ break; } + case _GUARD_BIT_IS_SET_POP: { + CHECK_STACK_BOUNDS(-1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + + case _GUARD_BIT_IS_UNSET_POP: { + CHECK_STACK_BOUNDS(-1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + case _GUARD_IS_NONE_POP: { JitOptRef val; val = stack_pointer[-1]; From cf71e34940e2314ee7ca00961d86a7172286eeea Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 21 Jan 2026 19:21:02 +0200 Subject: [PATCH 039/133] gh-77188: Add pickle tests for objects with slots (GH-144116) --- Lib/test/picklecommon.py | 39 ++++++++++++++++++++- Lib/test/pickletester.py | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/Lib/test/picklecommon.py b/Lib/test/picklecommon.py index fece50f17fe..4c19b6c421f 100644 --- a/Lib/test/picklecommon.py +++ b/Lib/test/picklecommon.py @@ -26,7 +26,7 @@ def __getinitargs__(self): E.__module__ = "__main__" # Simple mutable object. -class Object: +class Object(object): pass # Hashable immutable key object containing unheshable mutable data. @@ -38,6 +38,43 @@ def __reduce__(self): # Shouldn't support the recursion itself return K, (self.value,) +class WithSlots(object): + __slots__ = ('a', 'b') + +class WithSlotsSubclass(WithSlots): + __slots__ = ('c',) + +class WithSlotsAndDict(object): + __slots__ = ('a', '__dict__') + +class WithPrivateAttrs(object): + def __init__(self, a): + self.__private = a + def get(self): + return self.__private + +class WithPrivateAttrsSubclass(WithPrivateAttrs): + def __init__(self, a, b): + super().__init__(a) + self.__private = b + def get2(self): + return self.__private + +class WithPrivateSlots(object): + __slots__ = ('__private',) + def __init__(self, a): + self.__private = a + def get(self): + return self.__private + +class WithPrivateSlotsSubclass(WithPrivateSlots): + __slots__ = ('__private',) + def __init__(self, a, b): + super().__init__(a) + self.__private = b + def get2(self): + return self.__private + # For test_misc class myint(int): def __init__(self, x): diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 2e362ac1b02..d2b8d036bfd 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -4118,6 +4118,82 @@ def test_c_methods(self): with self.subTest(proto=proto, descr=descr): self.assertRaises(TypeError, self.dumps, descr, proto) + def test_object_with_attrs(self): + obj = Object() + obj.a = 1 + for proto in protocols: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.a, obj.a) + + def test_object_with_slots(self): + obj = WithSlots() + obj.a = 1 + self.assertRaises(TypeError, self.dumps, obj, 0) + self.assertRaises(TypeError, self.dumps, obj, 1) + for proto in protocols[2:]: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.a, obj.a) + self.assertNotHasAttr(unpickled, 'b') + + obj = WithSlotsSubclass() + obj.a = 1 + obj.c = 2 + self.assertRaises(TypeError, self.dumps, obj, 0) + self.assertRaises(TypeError, self.dumps, obj, 1) + for proto in protocols[2:]: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.a, obj.a) + self.assertEqual(unpickled.c, obj.c) + self.assertNotHasAttr(unpickled, 'b') + + obj = WithSlotsAndDict() + obj.a = 1 + obj.c = 2 + self.assertRaises(TypeError, self.dumps, obj, 0) + self.assertRaises(TypeError, self.dumps, obj, 1) + for proto in protocols[2:]: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.a, obj.a) + self.assertEqual(unpickled.c, obj.c) + self.assertEqual(unpickled.__dict__, obj.__dict__) + self.assertNotHasAttr(unpickled, 'b') + + def test_object_with_private_attrs(self): + obj = WithPrivateAttrs(1) + for proto in protocols: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.get(), obj.get()) + + obj = WithPrivateAttrsSubclass(1, 2) + for proto in protocols: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.get(), obj.get()) + self.assertEqual(unpickled.get2(), obj.get2()) + + def test_object_with_private_slots(self): + obj = WithPrivateSlots(1) + self.assertRaises(TypeError, self.dumps, obj, 0) + self.assertRaises(TypeError, self.dumps, obj, 1) + for proto in protocols[2:]: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.get(), obj.get()) + + obj = WithPrivateSlotsSubclass(1, 2) + self.assertRaises(TypeError, self.dumps, obj, 0) + self.assertRaises(TypeError, self.dumps, obj, 1) + for proto in protocols[2:]: + with self.subTest(proto=proto): + unpickled = self.loads(self.dumps(obj, proto)) + self.assertEqual(unpickled.get(), obj.get()) + self.assertEqual(unpickled.get2(), obj.get2()) + def test_compat_pickle(self): if self.py_version < (3, 4): self.skipTest("doesn't work in Python < 3.4'") From 6181b69970b93fc74d74c97ce6543c0d1b6a258c Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Wed, 21 Jan 2026 14:31:58 -0800 Subject: [PATCH 040/133] GH-143941: Move WASI-related files to Platforms/WASI (GH-143942) Along the way, leave a deprecated Tools/wasm/wasi/__main__.py behind for backwards-compatibility. Co-authored-by: Zachary Ware --- .github/CODEOWNERS | 1 + .github/workflows/reusable-wasi.yml | 8 +- ...-01-16-14-27-53.gh-issue-143941.TiaE-3.rst | 3 + Platforms/WASI/.ruff.toml | 25 + Platforms/WASI/README.md | 59 ++ Platforms/WASI/__main__.py | 557 +++++++++++++++++ .../WASI}/config.site-wasm32-wasi | 0 .../wasm/wasi => Platforms/WASI}/config.toml | 0 .../wasi => Platforms/WASI}/wasmtime.toml | 0 Tools/build/compute-changes.py | 4 +- Tools/wasm/README.md | 45 +- Tools/wasm/wasi.py | 7 - Tools/wasm/wasi/__main__.py | 566 +----------------- 13 files changed, 673 insertions(+), 602 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-01-16-14-27-53.gh-issue-143941.TiaE-3.rst create mode 100644 Platforms/WASI/.ruff.toml create mode 100644 Platforms/WASI/README.md create mode 100644 Platforms/WASI/__main__.py rename {Tools/wasm/wasi => Platforms/WASI}/config.site-wasm32-wasi (100%) rename {Tools/wasm/wasi => Platforms/WASI}/config.toml (100%) rename {Tools/wasm/wasi => Platforms/WASI}/wasmtime.toml (100%) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 440d4c005c6..6b6074be0a5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -176,6 +176,7 @@ Tools/wasm/config.site-wasm32-emscripten @freakboy3742 @emmatyping Tools/wasm/emscripten @freakboy3742 @emmatyping # WebAssembly (WASI) +Platforms/WASI @brettcannon @emmatyping @savannahostrowski Tools/wasm/wasi-env @brettcannon @emmatyping @savannahostrowski Tools/wasm/wasi.py @brettcannon @emmatyping @savannahostrowski Tools/wasm/wasi @brettcannon @emmatyping @savannahostrowski diff --git a/.github/workflows/reusable-wasi.yml b/.github/workflows/reusable-wasi.yml index 4b03712eb1e..3c81f6ef82d 100644 --- a/.github/workflows/reusable-wasi.yml +++ b/.github/workflows/reusable-wasi.yml @@ -47,14 +47,14 @@ jobs: - name: "Runner image version" run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV" - name: "Configure build Python" - run: python3 Tools/wasm/wasi configure-build-python -- --config-cache --with-pydebug + run: python3 Platforms/WASI configure-build-python -- --config-cache --with-pydebug - name: "Make build Python" - run: python3 Tools/wasm/wasi make-build-python + run: python3 Platforms/WASI make-build-python - name: "Configure host" # `--with-pydebug` inferred from configure-build-python - run: python3 Tools/wasm/wasi configure-host -- --config-cache + run: python3 Platforms/WASI configure-host -- --config-cache - name: "Make host" - run: python3 Tools/wasm/wasi make-host + run: python3 Platforms/WASI make-host - name: "Display build info" run: make --directory "${CROSS_BUILD_WASI}" pythoninfo - name: "Test" diff --git a/Misc/NEWS.d/next/Build/2026-01-16-14-27-53.gh-issue-143941.TiaE-3.rst b/Misc/NEWS.d/next/Build/2026-01-16-14-27-53.gh-issue-143941.TiaE-3.rst new file mode 100644 index 00000000000..68839364a0d --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-01-16-14-27-53.gh-issue-143941.TiaE-3.rst @@ -0,0 +1,3 @@ +Move WASI-related files to :file:`Platforms/WASI`. Along the way, leave a +deprecated :file:`Tools/wasm/wasi/__main__.py` behind for +backwards-compatibility. diff --git a/Platforms/WASI/.ruff.toml b/Platforms/WASI/.ruff.toml new file mode 100644 index 00000000000..3d8e59fa3f2 --- /dev/null +++ b/Platforms/WASI/.ruff.toml @@ -0,0 +1,25 @@ +extend = "../../.ruff.toml" # Inherit the project-wide settings + +[format] +preview = true +docstring-code-format = true + +[lint] +select = [ + "C4", # flake8-comprehensions + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "ISC", # flake8-implicit-str-concat + "LOG", # flake8-logging + "PGH", # pygrep-hooks + "PT", # flake8-pytest-style + "PYI", # flake8-pyi + "RUF100", # Ban unused `# noqa` comments + "UP", # pyupgrade + "W", # pycodestyle + "YTT", # flake8-2020 +] +ignore = [ + "E501", # Line too long +] diff --git a/Platforms/WASI/README.md b/Platforms/WASI/README.md new file mode 100644 index 00000000000..62c82924d43 --- /dev/null +++ b/Platforms/WASI/README.md @@ -0,0 +1,59 @@ +# Python WASI (wasm32-wasi) build + +**WASI support is [tier 2](https://peps.python.org/pep-0011/#tier-2).** + +This directory contains configuration and helpers to facilitate cross +compilation of CPython to WebAssembly (WASM) using WASI. WASI builds +use WASM runtimes such as [wasmtime](https://wasmtime.dev/). + +**NOTE**: If you are looking for general information about WebAssembly that is +not directly related to CPython, please see https://github.com/psf/webassembly. + +## Build + +See [the devguide on how to build and run for WASI](https://devguide.python.org/getting-started/setup-building/#wasi). + +## Detecting WASI builds + +### Python code + +```python +import os, sys + +if sys.platform == "wasi": + # Python on WASI + ... + +if os.name == "posix": + # WASM platforms identify as POSIX-like. + # Windows does not provide os.uname(). + machine = os.uname().machine + if machine.startswith("wasm"): + # WebAssembly (wasm32, wasm64 potentially in the future) +``` + +```python +>>> import os, sys +>>> os.uname() +posix.uname_result( + sysname='wasi', + nodename='(none)', + release='0.0.0', + version='0.0.0', + machine='wasm32' +) +>>> os.name +'posix' +>>> sys.platform +'wasi' +``` + +### C code + +WASI SDK defines several built-in macros. You can dump a full list of built-ins +with ``/path/to/wasi-sdk/bin/clang -dM -E - < /dev/null``. + +* WebAssembly ``__wasm__`` (also ``__wasm``) +* wasm32 ``__wasm32__`` (also ``__wasm32``) +* wasm64 ``__wasm64__`` +* WASI ``__wasi__`` diff --git a/Platforms/WASI/__main__.py b/Platforms/WASI/__main__.py new file mode 100644 index 00000000000..8302432fd2f --- /dev/null +++ b/Platforms/WASI/__main__.py @@ -0,0 +1,557 @@ +#!/usr/bin/env python3 + +import argparse +import contextlib +import functools +import os + +import tomllib + +try: + from os import process_cpu_count as cpu_count +except ImportError: + from os import cpu_count +import pathlib +import shutil +import subprocess +import sys +import sysconfig +import tempfile + +CHECKOUT = HERE = pathlib.Path(__file__).parent + +while CHECKOUT != CHECKOUT.parent: + if (CHECKOUT / "configure").is_file(): + break + CHECKOUT = CHECKOUT.parent +else: + raise FileNotFoundError( + "Unable to find the root of the CPython checkout by looking for 'configure'" + ) + +CROSS_BUILD_DIR = CHECKOUT / "cross-build" +# Build platform can also be found via `config.guess`. +BUILD_DIR = CROSS_BUILD_DIR / sysconfig.get_config_var("BUILD_GNU_TYPE") + +LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" +LOCAL_SETUP_MARKER = ( + b"# Generated by Platforms/WASI .\n" + b"# Required to statically build extension modules." +) + +WASI_SDK_VERSION = 29 + +WASMTIME_VAR_NAME = "WASMTIME" +WASMTIME_HOST_RUNNER_VAR = f"{{{WASMTIME_VAR_NAME}}}" + + +def separator(): + """Print a separator line across the terminal width.""" + try: + tput_output = subprocess.check_output( + ["tput", "cols"], encoding="utf-8" + ) + except subprocess.CalledProcessError: + terminal_width = 80 + else: + terminal_width = int(tput_output.strip()) + print("⎯" * terminal_width) + + +def log(emoji, message, *, spacing=None): + """Print a notification with an emoji. + + If 'spacing' is None, calculate the spacing based on the number of code points + in the emoji as terminals "eat" a space when the emoji has multiple code points. + """ + if spacing is None: + spacing = " " if len(emoji) == 1 else " " + print("".join([emoji, spacing, message])) + + +def updated_env(updates={}): + """Create a new dict representing the environment to use. + + The changes made to the execution environment are printed out. + """ + env_defaults = {} + # https://reproducible-builds.org/docs/source-date-epoch/ + git_epoch_cmd = ["git", "log", "-1", "--pretty=%ct"] + try: + epoch = subprocess.check_output( + git_epoch_cmd, encoding="utf-8" + ).strip() + env_defaults["SOURCE_DATE_EPOCH"] = epoch + except subprocess.CalledProcessError: + pass # Might be building from a tarball. + # This layering lets SOURCE_DATE_EPOCH from os.environ takes precedence. + environment = env_defaults | os.environ | updates + + env_diff = {} + for key, value in environment.items(): + if os.environ.get(key) != value: + env_diff[key] = value + + env_vars = ( + f"\n {key}={item}" for key, item in sorted(env_diff.items()) + ) + log("🌎", f"Environment changes:{''.join(env_vars)}") + + return environment + + +def subdir(working_dir, *, clean_ok=False): + """Decorator to change to a working directory.""" + + def decorator(func): + @functools.wraps(func) + def wrapper(context): + nonlocal working_dir + + if callable(working_dir): + working_dir = working_dir(context) + separator() + log("📁", os.fsdecode(working_dir)) + if ( + clean_ok + and getattr(context, "clean", False) + and working_dir.exists() + ): + log("🚮", "Deleting directory (--clean)...") + shutil.rmtree(working_dir) + + working_dir.mkdir(parents=True, exist_ok=True) + + with contextlib.chdir(working_dir): + return func(context, working_dir) + + return wrapper + + return decorator + + +def call(command, *, context=None, quiet=False, logdir=None, **kwargs): + """Execute a command. + + If 'quiet' is true, then redirect stdout and stderr to a temporary file. + """ + if context is not None: + quiet = context.quiet + logdir = context.logdir + elif quiet and logdir is None: + raise ValueError("When quiet is True, logdir must be specified") + + log("❯", " ".join(map(str, command)), spacing=" ") + if not quiet: + stdout = None + stderr = None + else: + stdout = tempfile.NamedTemporaryFile( + "w", + encoding="utf-8", + delete=False, + dir=logdir, + prefix="cpython-wasi-", + suffix=".log", + ) + stderr = subprocess.STDOUT + log("📝", f"Logging output to {stdout.name} (--quiet)...") + + subprocess.check_call(command, **kwargs, stdout=stdout, stderr=stderr) + + +def build_python_path(): + """The path to the build Python binary.""" + binary = BUILD_DIR / "python" + if not binary.is_file(): + binary = binary.with_suffix(".exe") + if not binary.is_file(): + raise FileNotFoundError( + f"Unable to find `python(.exe)` in {BUILD_DIR}" + ) + + return binary + + +def build_python_is_pydebug(): + """Find out if the build Python is a pydebug build.""" + test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)" + result = subprocess.run( + [build_python_path(), "-c", test], + capture_output=True, + ) + return bool(result.returncode) + + +@subdir(BUILD_DIR, clean_ok=True) +def configure_build_python(context, working_dir): + """Configure the build/host Python.""" + if LOCAL_SETUP.exists(): + if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: + log("👍", f"{LOCAL_SETUP} exists ...") + else: + log("⚠️", f"{LOCAL_SETUP} exists, but has unexpected contents") + else: + log("📝", f"Creating {LOCAL_SETUP} ...") + LOCAL_SETUP.write_bytes(LOCAL_SETUP_MARKER) + + configure = [os.path.relpath(CHECKOUT / "configure", working_dir)] + if context.args: + configure.extend(context.args) + + call(configure, context=context) + + +@subdir(BUILD_DIR) +def make_build_python(context, working_dir): + """Make/build the build Python.""" + call(["make", "--jobs", str(cpu_count()), "all"], context=context) + + binary = build_python_path() + cmd = [ + binary, + "-c", + "import sys; " + "print(f'{sys.version_info.major}.{sys.version_info.minor}')", + ] + version = subprocess.check_output(cmd, encoding="utf-8").strip() + + log("🎉", f"{binary} {version}") + + +def find_wasi_sdk(config): + """Find the path to the WASI SDK.""" + wasi_sdk_path = None + wasi_sdk_version = config["targets"]["wasi-sdk"] + + if wasi_sdk_path_env_var := os.environ.get("WASI_SDK_PATH"): + wasi_sdk_path = pathlib.Path(wasi_sdk_path_env_var) + else: + opt_path = pathlib.Path("/opt") + # WASI SDK versions have a ``.0`` suffix, but it's a constant; the WASI SDK team + # has said they don't plan to ever do a point release and all of their Git tags + # lack the ``.0`` suffix. + # Starting with WASI SDK 23, the tarballs went from containing a directory named + # ``wasi-sdk-{WASI_SDK_VERSION}.0`` to e.g. + # ``wasi-sdk-{WASI_SDK_VERSION}.0-x86_64-linux``. + potential_sdks = [ + path + for path in opt_path.glob(f"wasi-sdk-{wasi_sdk_version}.0*") + if path.is_dir() + ] + if len(potential_sdks) == 1: + wasi_sdk_path = potential_sdks[0] + elif (default_path := opt_path / "wasi-sdk").is_dir(): + wasi_sdk_path = default_path + + # Starting with WASI SDK 25, a VERSION file is included in the root + # of the SDK directory that we can read to warn folks when they are using + # an unsupported version. + if wasi_sdk_path and (version_file := wasi_sdk_path / "VERSION").is_file(): + version_details = version_file.read_text(encoding="utf-8") + found_version = version_details.splitlines()[0] + # Make sure there's a trailing dot to avoid false positives if somehow the + # supported version is a prefix of the found version (e.g. `25` and `2567`). + if not found_version.startswith(f"{wasi_sdk_version}."): + major_version = found_version.partition(".")[0] + log( + "⚠️", + f" Found WASI SDK {major_version}, " + f"but WASI SDK {wasi_sdk_version} is the supported version", + ) + + return wasi_sdk_path + + +def wasi_sdk_env(context): + """Calculate environment variables for building with wasi-sdk.""" + wasi_sdk_path = context.wasi_sdk_path + sysroot = wasi_sdk_path / "share" / "wasi-sysroot" + env = { + "CC": "clang", + "CPP": "clang-cpp", + "CXX": "clang++", + "AR": "llvm-ar", + "RANLIB": "ranlib", + } + + for env_var, binary_name in list(env.items()): + env[env_var] = os.fsdecode(wasi_sdk_path / "bin" / binary_name) + + if not wasi_sdk_path.name.startswith("wasi-sdk"): + for compiler in ["CC", "CPP", "CXX"]: + env[compiler] += f" --sysroot={sysroot}" + + env["PKG_CONFIG_PATH"] = "" + env["PKG_CONFIG_LIBDIR"] = os.pathsep.join( + map( + os.fsdecode, + [sysroot / "lib" / "pkgconfig", sysroot / "share" / "pkgconfig"], + ) + ) + env["PKG_CONFIG_SYSROOT_DIR"] = os.fsdecode(sysroot) + + env["WASI_SDK_PATH"] = os.fsdecode(wasi_sdk_path) + env["WASI_SYSROOT"] = os.fsdecode(sysroot) + + env["PATH"] = os.pathsep.join([ + os.fsdecode(wasi_sdk_path / "bin"), + os.environ["PATH"], + ]) + + return env + + +@subdir(lambda context: CROSS_BUILD_DIR / context.host_triple, clean_ok=True) +def configure_wasi_python(context, working_dir): + """Configure the WASI/host build.""" + if not context.wasi_sdk_path or not context.wasi_sdk_path.exists(): + raise ValueError( + "WASI-SDK not found; " + "download from " + "https://github.com/WebAssembly/wasi-sdk and/or " + "specify via $WASI_SDK_PATH or --wasi-sdk" + ) + + config_site = os.fsdecode(HERE / "config.site-wasm32-wasi") + + wasi_build_dir = working_dir.relative_to(CHECKOUT) + + python_build_dir = BUILD_DIR / "build" + lib_dirs = list(python_build_dir.glob("lib.*")) + assert len(lib_dirs) == 1, ( + f"Expected a single lib.* directory in {python_build_dir}" + ) + lib_dir = os.fsdecode(lib_dirs[0]) + python_version = lib_dir.rpartition("-")[-1] + sysconfig_data_dir = ( + f"{wasi_build_dir}/build/lib.wasi-wasm32-{python_version}" + ) + + # Use PYTHONPATH to include sysconfig data which must be anchored to the + # WASI guest's `/` directory. + args = { + "PYTHONPATH": f"/{sysconfig_data_dir}", + "PYTHON_WASM": working_dir / "python.wasm", + } + # Check dynamically for wasmtime in case it was specified manually via + # `--host-runner`. + if WASMTIME_HOST_RUNNER_VAR in context.host_runner: + if wasmtime := shutil.which("wasmtime"): + args[WASMTIME_VAR_NAME] = wasmtime + else: + raise FileNotFoundError( + "wasmtime not found; download from " + "https://github.com/bytecodealliance/wasmtime" + ) + host_runner = context.host_runner.format_map(args) + env_additions = {"CONFIG_SITE": config_site, "HOSTRUNNER": host_runner} + build_python = os.fsdecode(build_python_path()) + # The path to `configure` MUST be relative, else `python.wasm` is unable + # to find the stdlib due to Python not recognizing that it's being + # executed from within a checkout. + configure = [ + os.path.relpath(CHECKOUT / "configure", working_dir), + f"--host={context.host_triple}", + f"--build={BUILD_DIR.name}", + f"--with-build-python={build_python}", + ] + if build_python_is_pydebug(): + configure.append("--with-pydebug") + if context.args: + configure.extend(context.args) + call( + configure, + env=updated_env(env_additions | wasi_sdk_env(context)), + context=context, + ) + + python_wasm = working_dir / "python.wasm" + exec_script = working_dir / "python.sh" + with exec_script.open("w", encoding="utf-8") as file: + file.write(f'#!/bin/sh\nexec {host_runner} {python_wasm} "$@"\n') + exec_script.chmod(0o755) + log("🏃", f"Created {exec_script} (--host-runner)... ") + sys.stdout.flush() + + +@subdir(lambda context: CROSS_BUILD_DIR / context.host_triple) +def make_wasi_python(context, working_dir): + """Run `make` for the WASI/host build.""" + call( + ["make", "--jobs", str(cpu_count()), "all"], + env=updated_env(), + context=context, + ) + + exec_script = working_dir / "python.sh" + call([exec_script, "--version"], quiet=False) + log( + "🎉", + f"Use `{exec_script.relative_to(context.init_dir)}` " + "to run CPython w/ the WASI host specified by --host-runner", + ) + + +def clean_contents(context): + """Delete all files created by this script.""" + if CROSS_BUILD_DIR.exists(): + log("🧹", f"Deleting {CROSS_BUILD_DIR} ...") + shutil.rmtree(CROSS_BUILD_DIR) + + if LOCAL_SETUP.exists(): + if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: + log("🧹", f"Deleting generated {LOCAL_SETUP} ...") + + +def build_steps(*steps): + """Construct a command from other steps.""" + + def builder(context): + for step in steps: + step(context) + + return builder + + +def main(): + with (HERE / "config.toml").open("rb") as file: + config = tomllib.load(file) + default_wasi_sdk = find_wasi_sdk(config) + default_host_triple = config["targets"]["host-triple"] + default_host_runner = ( + f"{WASMTIME_HOST_RUNNER_VAR} run " + # For setting PYTHONPATH to the sysconfig data directory. + "--env PYTHONPATH={PYTHONPATH} " + # Map the checkout to / to load the stdlib from /Lib. + f"--dir {os.fsdecode(CHECKOUT)}::/ " + # Flags involving --optimize, --codegen, --debug, --wasm, and --wasi can be kept + # in a config file. + # We are using such a file to act as defaults in case a user wants to override + # only some of the settings themselves, make it easy to modify settings + # post-build so that they immediately apply to the Makefile instead of having to + # regenerate it, and allow for easy copying of the settings for anyone else who + # may want to use them. + f"--config {os.fsdecode(HERE / 'wasmtime.toml')}" + ) + default_logdir = pathlib.Path(tempfile.gettempdir()) + + parser = argparse.ArgumentParser() + subcommands = parser.add_subparsers(dest="subcommand") + build = subcommands.add_parser("build", help="Build everything") + configure_build = subcommands.add_parser( + "configure-build-python", help="Run `configure` for the build Python" + ) + make_build = subcommands.add_parser( + "make-build-python", help="Run `make` for the build Python" + ) + build_python = subcommands.add_parser( + "build-python", help="Build the build Python" + ) + configure_host = subcommands.add_parser( + "configure-host", + help="Run `configure` for the " + "host/WASI (pydebug builds " + "are inferred from the build " + "Python)", + ) + make_host = subcommands.add_parser( + "make-host", help="Run `make` for the host/WASI" + ) + build_host = subcommands.add_parser( + "build-host", help="Build the host/WASI Python" + ) + subcommands.add_parser( + "clean", help="Delete files and directories created by this script" + ) + for subcommand in ( + build, + configure_build, + make_build, + build_python, + configure_host, + make_host, + build_host, + ): + subcommand.add_argument( + "--quiet", + action="store_true", + default=False, + dest="quiet", + help="Redirect output from subprocesses to a log file", + ) + subcommand.add_argument( + "--logdir", + type=pathlib.Path, + default=default_logdir, + help=f"Directory to store log files; defaults to {default_logdir}", + ) + for subcommand in ( + configure_build, + configure_host, + build_python, + build_host, + ): + subcommand.add_argument( + "--clean", + action="store_true", + default=False, + dest="clean", + help="Delete any relevant directories before building", + ) + for subcommand in ( + build, + configure_build, + configure_host, + build_python, + build_host, + ): + subcommand.add_argument( + "args", nargs="*", help="Extra arguments to pass to `configure`" + ) + for subcommand in build, configure_host, build_host: + subcommand.add_argument( + "--wasi-sdk", + type=pathlib.Path, + dest="wasi_sdk_path", + default=default_wasi_sdk, + help=f"Path to the WASI SDK; defaults to {default_wasi_sdk}", + ) + subcommand.add_argument( + "--host-runner", + action="store", + default=default_host_runner, + dest="host_runner", + help="Command template for running the WASI host; defaults to " + f"`{default_host_runner}`", + ) + for subcommand in build, configure_host, make_host, build_host: + subcommand.add_argument( + "--host-triple", + action="store", + default=default_host_triple, + help="The target triple for the WASI host build; " + f"defaults to {default_host_triple}", + ) + + context = parser.parse_args() + context.init_dir = pathlib.Path().absolute() + + build_build_python = build_steps(configure_build_python, make_build_python) + build_wasi_python = build_steps(configure_wasi_python, make_wasi_python) + + dispatch = { + "configure-build-python": configure_build_python, + "make-build-python": make_build_python, + "build-python": build_build_python, + "configure-host": configure_wasi_python, + "make-host": make_wasi_python, + "build-host": build_wasi_python, + "build": build_steps(build_build_python, build_wasi_python), + "clean": clean_contents, + } + dispatch[context.subcommand](context) + + +if __name__ == "__main__": + main() diff --git a/Tools/wasm/wasi/config.site-wasm32-wasi b/Platforms/WASI/config.site-wasm32-wasi similarity index 100% rename from Tools/wasm/wasi/config.site-wasm32-wasi rename to Platforms/WASI/config.site-wasm32-wasi diff --git a/Tools/wasm/wasi/config.toml b/Platforms/WASI/config.toml similarity index 100% rename from Tools/wasm/wasi/config.toml rename to Platforms/WASI/config.toml diff --git a/Tools/wasm/wasi/wasmtime.toml b/Platforms/WASI/wasmtime.toml similarity index 100% rename from Tools/wasm/wasi/wasmtime.toml rename to Platforms/WASI/wasmtime.toml diff --git a/Tools/build/compute-changes.py b/Tools/build/compute-changes.py index 88b7856b9c7..08aba5ef542 100644 --- a/Tools/build/compute-changes.py +++ b/Tools/build/compute-changes.py @@ -50,7 +50,7 @@ ANDROID_DIRS = frozenset({"Android"}) IOS_DIRS = frozenset({"Apple", "iOS"}) MACOS_DIRS = frozenset({"Mac"}) -WASI_DIRS = frozenset({Path("Tools", "wasm")}) +WASI_DIRS = frozenset({Path("Platforms", "WASI")}) LIBRARY_FUZZER_PATHS = frozenset({ # All C/CPP fuzzers. @@ -194,7 +194,7 @@ def get_file_platform(file: Path) -> str | None: return "ios" if first_part in ANDROID_DIRS: return "android" - if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: # Tools/wasm/ + if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS: return "wasi" return None diff --git a/Tools/wasm/README.md b/Tools/wasm/README.md index 35685db07b1..46228a5212a 100644 --- a/Tools/wasm/README.md +++ b/Tools/wasm/README.md @@ -1,19 +1,16 @@ -# Python WebAssembly (WASM) build +# Python Emscripten (wasm32-emscripten) build -**WASI support is [tier 2](https://peps.python.org/pep-0011/#tier-2).** **Emscripten support is [tier 3](https://peps.python.org/pep-0011/#tier-3).** This directory contains configuration and helpers to facilitate cross -compilation of CPython to WebAssembly (WASM). Python supports Emscripten -(*wasm32-emscripten*) and WASI (*wasm32-wasi*) targets. Emscripten builds -run in modern browsers and JavaScript runtimes like *Node.js*. WASI builds -use WASM runtimes such as *wasmtime*. +compilation of CPython to WebAssembly (WASM) using Emscripten. Emscripten builds +run in modern browsers and JavaScript runtimes like *Node.js*. + +For WASI builds, see [Platforms/WASI](../../Platforms/WASI/README.md). **NOTE**: If you are looking for general information about WebAssembly that is not directly related to CPython, please see https://github.com/psf/webassembly. -## Emscripten (wasm32-emscripten) - ### Build See [the devguide instructions for building for Emscripten](https://devguide.python.org/getting-started/setup-building/#emscripten). @@ -192,11 +189,7 @@ #### In the browser - Test modules are disabled by default. Use ``--enable-test-modules`` build test modules like ``_testcapi``. -## WASI (wasm32-wasi) - -See [the devguide on how to build and run for WASI](https://devguide.python.org/getting-started/setup-building/#wasi). - -## Detecting WebAssembly builds +## Detecting Emscripten builds ### Python code @@ -206,9 +199,6 @@ ### Python code if sys.platform == "emscripten": # Python on Emscripten ... -if sys.platform == "wasi": - # Python on WASI - ... if os.name == "posix": # WASM platforms identify as POSIX-like. @@ -251,31 +241,14 @@ ### Python code ) ``` -```python ->>> import os, sys ->>> os.uname() -posix.uname_result( - sysname='wasi', - nodename='(none)', - release='0.0.0', - version='0.0.0', - machine='wasm32' -) ->>> os.name -'posix' ->>> sys.platform -'wasi' -``` - ### C code -Emscripten SDK and WASI SDK define several built-in macros. You can dump a -full list of built-ins with ``emcc -dM -E - < /dev/null`` and -``/path/to/wasi-sdk/bin/clang -dM -E - < /dev/null``. +Emscripten SDK defines several built-in macros. You can dump a full list of +built-ins with ``emcc -dM -E - < /dev/null``. * WebAssembly ``__wasm__`` (also ``__wasm``) * wasm32 ``__wasm32__`` (also ``__wasm32``) * wasm64 ``__wasm64__`` * Emscripten ``__EMSCRIPTEN__`` (also ``EMSCRIPTEN``) * Emscripten version ``__EMSCRIPTEN_major__``, ``__EMSCRIPTEN_minor__``, ``__EMSCRIPTEN_tiny__`` -* WASI ``__wasi__`` + diff --git a/Tools/wasm/wasi.py b/Tools/wasm/wasi.py index af55e03d10f..72a708c45c0 100644 --- a/Tools/wasm/wasi.py +++ b/Tools/wasm/wasi.py @@ -1,12 +1,5 @@ if __name__ == "__main__": import pathlib import runpy - import sys - - print( - "⚠️ WARNING: This script is deprecated and slated for removal in Python 3.20; " - "execute the `wasi/` directory instead (i.e. `python Tools/wasm/wasi`)\n", - file=sys.stderr, - ) runpy.run_path(pathlib.Path(__file__).parent / "wasi", run_name="__main__") diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index 3d9a2472d4d..e6126eddde1 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -1,554 +1,14 @@ -#!/usr/bin/env python3 - -import argparse -import contextlib -import functools -import os - -import tomllib - -try: - from os import process_cpu_count as cpu_count -except ImportError: - from os import cpu_count -import pathlib -import shutil -import subprocess -import sys -import sysconfig -import tempfile - -HERE = pathlib.Path(__file__).parent - -# Path is: cpython/Tools/wasm/wasi -CHECKOUT = HERE.parent.parent.parent -assert (CHECKOUT / "configure").is_file(), ( - "Please update the location of the file" -) - -CROSS_BUILD_DIR = CHECKOUT / "cross-build" -# Build platform can also be found via `config.guess`. -BUILD_DIR = CROSS_BUILD_DIR / sysconfig.get_config_var("BUILD_GNU_TYPE") - -LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local" -LOCAL_SETUP_MARKER = ( - b"# Generated by Tools/wasm/wasi .\n" - b"# Required to statically build extension modules." -) - -WASI_SDK_VERSION = 29 - -WASMTIME_VAR_NAME = "WASMTIME" -WASMTIME_HOST_RUNNER_VAR = f"{{{WASMTIME_VAR_NAME}}}" - - -def separator(): - """Print a separator line across the terminal width.""" - try: - tput_output = subprocess.check_output( - ["tput", "cols"], encoding="utf-8" - ) - except subprocess.CalledProcessError: - terminal_width = 80 - else: - terminal_width = int(tput_output.strip()) - print("⎯" * terminal_width) - - -def log(emoji, message, *, spacing=None): - """Print a notification with an emoji. - - If 'spacing' is None, calculate the spacing based on the number of code points - in the emoji as terminals "eat" a space when the emoji has multiple code points. - """ - if spacing is None: - spacing = " " if len(emoji) == 1 else " " - print("".join([emoji, spacing, message])) - - -def updated_env(updates={}): - """Create a new dict representing the environment to use. - - The changes made to the execution environment are printed out. - """ - env_defaults = {} - # https://reproducible-builds.org/docs/source-date-epoch/ - git_epoch_cmd = ["git", "log", "-1", "--pretty=%ct"] - try: - epoch = subprocess.check_output( - git_epoch_cmd, encoding="utf-8" - ).strip() - env_defaults["SOURCE_DATE_EPOCH"] = epoch - except subprocess.CalledProcessError: - pass # Might be building from a tarball. - # This layering lets SOURCE_DATE_EPOCH from os.environ takes precedence. - environment = env_defaults | os.environ | updates - - env_diff = {} - for key, value in environment.items(): - if os.environ.get(key) != value: - env_diff[key] = value - - env_vars = ( - f"\n {key}={item}" for key, item in sorted(env_diff.items()) - ) - log("🌎", f"Environment changes:{''.join(env_vars)}") - - return environment - - -def subdir(working_dir, *, clean_ok=False): - """Decorator to change to a working directory.""" - - def decorator(func): - @functools.wraps(func) - def wrapper(context): - nonlocal working_dir - - if callable(working_dir): - working_dir = working_dir(context) - separator() - log("📁", os.fsdecode(working_dir)) - if ( - clean_ok - and getattr(context, "clean", False) - and working_dir.exists() - ): - log("🚮", "Deleting directory (--clean)...") - shutil.rmtree(working_dir) - - working_dir.mkdir(parents=True, exist_ok=True) - - with contextlib.chdir(working_dir): - return func(context, working_dir) - - return wrapper - - return decorator - - -def call(command, *, context=None, quiet=False, logdir=None, **kwargs): - """Execute a command. - - If 'quiet' is true, then redirect stdout and stderr to a temporary file. - """ - if context is not None: - quiet = context.quiet - logdir = context.logdir - elif quiet and logdir is None: - raise ValueError("When quiet is True, logdir must be specified") - - log("❯", " ".join(map(str, command)), spacing=" ") - if not quiet: - stdout = None - stderr = None - else: - stdout = tempfile.NamedTemporaryFile( - "w", - encoding="utf-8", - delete=False, - dir=logdir, - prefix="cpython-wasi-", - suffix=".log", - ) - stderr = subprocess.STDOUT - log("📝", f"Logging output to {stdout.name} (--quiet)...") - - subprocess.check_call(command, **kwargs, stdout=stdout, stderr=stderr) - - -def build_python_path(): - """The path to the build Python binary.""" - binary = BUILD_DIR / "python" - if not binary.is_file(): - binary = binary.with_suffix(".exe") - if not binary.is_file(): - raise FileNotFoundError( - f"Unable to find `python(.exe)` in {BUILD_DIR}" - ) - - return binary - - -def build_python_is_pydebug(): - """Find out if the build Python is a pydebug build.""" - test = "import sys, test.support; sys.exit(test.support.Py_DEBUG)" - result = subprocess.run( - [build_python_path(), "-c", test], - capture_output=True, - ) - return bool(result.returncode) - - -@subdir(BUILD_DIR, clean_ok=True) -def configure_build_python(context, working_dir): - """Configure the build/host Python.""" - if LOCAL_SETUP.exists(): - if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: - log("👍", f"{LOCAL_SETUP} exists ...") - else: - log("⚠️", f"{LOCAL_SETUP} exists, but has unexpected contents") - else: - log("📝", f"Creating {LOCAL_SETUP} ...") - LOCAL_SETUP.write_bytes(LOCAL_SETUP_MARKER) - - configure = [os.path.relpath(CHECKOUT / "configure", working_dir)] - if context.args: - configure.extend(context.args) - - call(configure, context=context) - - -@subdir(BUILD_DIR) -def make_build_python(context, working_dir): - """Make/build the build Python.""" - call(["make", "--jobs", str(cpu_count()), "all"], context=context) - - binary = build_python_path() - cmd = [ - binary, - "-c", - "import sys; " - "print(f'{sys.version_info.major}.{sys.version_info.minor}')", - ] - version = subprocess.check_output(cmd, encoding="utf-8").strip() - - log("🎉", f"{binary} {version}") - - -def find_wasi_sdk(config): - """Find the path to the WASI SDK.""" - wasi_sdk_path = None - wasi_sdk_version = config["targets"]["wasi-sdk"] - - if wasi_sdk_path_env_var := os.environ.get("WASI_SDK_PATH"): - wasi_sdk_path = pathlib.Path(wasi_sdk_path_env_var) - else: - opt_path = pathlib.Path("/opt") - # WASI SDK versions have a ``.0`` suffix, but it's a constant; the WASI SDK team - # has said they don't plan to ever do a point release and all of their Git tags - # lack the ``.0`` suffix. - # Starting with WASI SDK 23, the tarballs went from containing a directory named - # ``wasi-sdk-{WASI_SDK_VERSION}.0`` to e.g. - # ``wasi-sdk-{WASI_SDK_VERSION}.0-x86_64-linux``. - potential_sdks = [ - path - for path in opt_path.glob(f"wasi-sdk-{wasi_sdk_version}.0*") - if path.is_dir() - ] - if len(potential_sdks) == 1: - wasi_sdk_path = potential_sdks[0] - elif (default_path := opt_path / "wasi-sdk").is_dir(): - wasi_sdk_path = default_path - - # Starting with WASI SDK 25, a VERSION file is included in the root - # of the SDK directory that we can read to warn folks when they are using - # an unsupported version. - if wasi_sdk_path and (version_file := wasi_sdk_path / "VERSION").is_file(): - version_details = version_file.read_text(encoding="utf-8") - found_version = version_details.splitlines()[0] - # Make sure there's a trailing dot to avoid false positives if somehow the - # supported version is a prefix of the found version (e.g. `25` and `2567`). - if not found_version.startswith(f"{wasi_sdk_version}."): - major_version = found_version.partition(".")[0] - log( - "⚠️", - f" Found WASI SDK {major_version}, " - f"but WASI SDK {wasi_sdk_version} is the supported version", - ) - - return wasi_sdk_path - - -def wasi_sdk_env(context): - """Calculate environment variables for building with wasi-sdk.""" - wasi_sdk_path = context.wasi_sdk_path - sysroot = wasi_sdk_path / "share" / "wasi-sysroot" - env = { - "CC": "clang", - "CPP": "clang-cpp", - "CXX": "clang++", - "AR": "llvm-ar", - "RANLIB": "ranlib", - } - - for env_var, binary_name in list(env.items()): - env[env_var] = os.fsdecode(wasi_sdk_path / "bin" / binary_name) - - if not wasi_sdk_path.name.startswith("wasi-sdk"): - for compiler in ["CC", "CPP", "CXX"]: - env[compiler] += f" --sysroot={sysroot}" - - env["PKG_CONFIG_PATH"] = "" - env["PKG_CONFIG_LIBDIR"] = os.pathsep.join( - map( - os.fsdecode, - [sysroot / "lib" / "pkgconfig", sysroot / "share" / "pkgconfig"], - ) - ) - env["PKG_CONFIG_SYSROOT_DIR"] = os.fsdecode(sysroot) - - env["WASI_SDK_PATH"] = os.fsdecode(wasi_sdk_path) - env["WASI_SYSROOT"] = os.fsdecode(sysroot) - - env["PATH"] = os.pathsep.join([ - os.fsdecode(wasi_sdk_path / "bin"), - os.environ["PATH"], - ]) - - return env - - -@subdir(lambda context: CROSS_BUILD_DIR / context.host_triple, clean_ok=True) -def configure_wasi_python(context, working_dir): - """Configure the WASI/host build.""" - if not context.wasi_sdk_path or not context.wasi_sdk_path.exists(): - raise ValueError( - "WASI-SDK not found; " - "download from " - "https://github.com/WebAssembly/wasi-sdk and/or " - "specify via $WASI_SDK_PATH or --wasi-sdk" - ) - - config_site = os.fsdecode(HERE / "config.site-wasm32-wasi") - - wasi_build_dir = working_dir.relative_to(CHECKOUT) - - python_build_dir = BUILD_DIR / "build" - lib_dirs = list(python_build_dir.glob("lib.*")) - assert len(lib_dirs) == 1, ( - f"Expected a single lib.* directory in {python_build_dir}" - ) - lib_dir = os.fsdecode(lib_dirs[0]) - python_version = lib_dir.rpartition("-")[-1] - sysconfig_data_dir = ( - f"{wasi_build_dir}/build/lib.wasi-wasm32-{python_version}" - ) - - # Use PYTHONPATH to include sysconfig data which must be anchored to the - # WASI guest's `/` directory. - args = { - "PYTHONPATH": f"/{sysconfig_data_dir}", - "PYTHON_WASM": working_dir / "python.wasm", - } - # Check dynamically for wasmtime in case it was specified manually via - # `--host-runner`. - if WASMTIME_HOST_RUNNER_VAR in context.host_runner: - if wasmtime := shutil.which("wasmtime"): - args[WASMTIME_VAR_NAME] = wasmtime - else: - raise FileNotFoundError( - "wasmtime not found; download from " - "https://github.com/bytecodealliance/wasmtime" - ) - host_runner = context.host_runner.format_map(args) - env_additions = {"CONFIG_SITE": config_site, "HOSTRUNNER": host_runner} - build_python = os.fsdecode(build_python_path()) - # The path to `configure` MUST be relative, else `python.wasm` is unable - # to find the stdlib due to Python not recognizing that it's being - # executed from within a checkout. - configure = [ - os.path.relpath(CHECKOUT / "configure", working_dir), - f"--host={context.host_triple}", - f"--build={BUILD_DIR.name}", - f"--with-build-python={build_python}", - ] - if build_python_is_pydebug(): - configure.append("--with-pydebug") - if context.args: - configure.extend(context.args) - call( - configure, - env=updated_env(env_additions | wasi_sdk_env(context)), - context=context, - ) - - python_wasm = working_dir / "python.wasm" - exec_script = working_dir / "python.sh" - with exec_script.open("w", encoding="utf-8") as file: - file.write(f'#!/bin/sh\nexec {host_runner} {python_wasm} "$@"\n') - exec_script.chmod(0o755) - log("🏃", f"Created {exec_script} (--host-runner)... ") - sys.stdout.flush() - - -@subdir(lambda context: CROSS_BUILD_DIR / context.host_triple) -def make_wasi_python(context, working_dir): - """Run `make` for the WASI/host build.""" - call( - ["make", "--jobs", str(cpu_count()), "all"], - env=updated_env(), - context=context, - ) - - exec_script = working_dir / "python.sh" - call([exec_script, "--version"], quiet=False) - log( - "🎉", - f"Use `{exec_script.relative_to(context.init_dir)}` " - "to run CPython w/ the WASI host specified by --host-runner", - ) - - -def clean_contents(context): - """Delete all files created by this script.""" - if CROSS_BUILD_DIR.exists(): - log("🧹", f"Deleting {CROSS_BUILD_DIR} ...") - shutil.rmtree(CROSS_BUILD_DIR) - - if LOCAL_SETUP.exists(): - if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: - log("🧹", f"Deleting generated {LOCAL_SETUP} ...") - - -def build_steps(*steps): - """Construct a command from other steps.""" - - def builder(context): - for step in steps: - step(context) - - return builder - - -def main(): - with (HERE / "config.toml").open("rb") as file: - config = tomllib.load(file) - default_wasi_sdk = find_wasi_sdk(config) - default_host_triple = config["targets"]["host-triple"] - default_host_runner = ( - f"{WASMTIME_HOST_RUNNER_VAR} run " - # For setting PYTHONPATH to the sysconfig data directory. - "--env PYTHONPATH={PYTHONPATH} " - # Map the checkout to / to load the stdlib from /Lib. - f"--dir {os.fsdecode(CHECKOUT)}::/ " - # Flags involving --optimize, --codegen, --debug, --wasm, and --wasi can be kept - # in a config file. - # We are using such a file to act as defaults in case a user wants to override - # only some of the settings themselves, make it easy to modify settings - # post-build so that they immediately apply to the Makefile instead of having to - # regenerate it, and allow for easy copying of the settings for anyone else who - # may want to use them. - f"--config {os.fsdecode(HERE / 'wasmtime.toml')}" - ) - default_logdir = pathlib.Path(tempfile.gettempdir()) - - parser = argparse.ArgumentParser() - subcommands = parser.add_subparsers(dest="subcommand") - build = subcommands.add_parser("build", help="Build everything") - configure_build = subcommands.add_parser( - "configure-build-python", help="Run `configure` for the build Python" - ) - make_build = subcommands.add_parser( - "make-build-python", help="Run `make` for the build Python" - ) - build_python = subcommands.add_parser( - "build-python", help="Build the build Python" - ) - configure_host = subcommands.add_parser( - "configure-host", - help="Run `configure` for the " - "host/WASI (pydebug builds " - "are inferred from the build " - "Python)", - ) - make_host = subcommands.add_parser( - "make-host", help="Run `make` for the host/WASI" - ) - build_host = subcommands.add_parser( - "build-host", help="Build the host/WASI Python" - ) - subcommands.add_parser( - "clean", help="Delete files and directories created by this script" - ) - for subcommand in ( - build, - configure_build, - make_build, - build_python, - configure_host, - make_host, - build_host, - ): - subcommand.add_argument( - "--quiet", - action="store_true", - default=False, - dest="quiet", - help="Redirect output from subprocesses to a log file", - ) - subcommand.add_argument( - "--logdir", - type=pathlib.Path, - default=default_logdir, - help=f"Directory to store log files; defaults to {default_logdir}", - ) - for subcommand in ( - configure_build, - configure_host, - build_python, - build_host, - ): - subcommand.add_argument( - "--clean", - action="store_true", - default=False, - dest="clean", - help="Delete any relevant directories before building", - ) - for subcommand in ( - build, - configure_build, - configure_host, - build_python, - build_host, - ): - subcommand.add_argument( - "args", nargs="*", help="Extra arguments to pass to `configure`" - ) - for subcommand in build, configure_host, build_host: - subcommand.add_argument( - "--wasi-sdk", - type=pathlib.Path, - dest="wasi_sdk_path", - default=default_wasi_sdk, - help=f"Path to the WASI SDK; defaults to {default_wasi_sdk}", - ) - subcommand.add_argument( - "--host-runner", - action="store", - default=default_host_runner, - dest="host_runner", - help="Command template for running the WASI host; defaults to " - f"`{default_host_runner}`", - ) - for subcommand in build, configure_host, make_host, build_host: - subcommand.add_argument( - "--host-triple", - action="store", - default=default_host_triple, - help="The target triple for the WASI host build; " - f"defaults to {default_host_triple}", - ) - - context = parser.parse_args() - context.init_dir = pathlib.Path().absolute() - - build_build_python = build_steps(configure_build_python, make_build_python) - build_wasi_python = build_steps(configure_wasi_python, make_wasi_python) - - dispatch = { - "configure-build-python": configure_build_python, - "make-build-python": make_build_python, - "build-python": build_build_python, - "configure-host": configure_wasi_python, - "make-host": make_wasi_python, - "build-host": build_wasi_python, - "build": build_steps(build_build_python, build_wasi_python), - "clean": clean_contents, - } - dispatch[context.subcommand](context) - - if __name__ == "__main__": - main() + import pathlib + import runpy + import sys + + print( + "⚠️ WARNING: This script is deprecated and slated for removal in Python 3.20; " + "execute the `Platforms/WASI/` directory instead (i.e. `python Platforms/WASI`)\n", + file=sys.stderr, + ) + + checkout = pathlib.Path(__file__).parent.parent.parent.parent + + runpy.run_path(checkout / "Platforms" / "WASI", run_name="__main__") From 0b08438ea693b7f78ec87e6a55e28d52709e19f4 Mon Sep 17 00:00:00 2001 From: reiden <65756407+reidenong@users.noreply.github.com> Date: Thu, 22 Jan 2026 17:37:45 +0800 Subject: [PATCH 041/133] gh-130415: Narrowing to constants in branches involving `is` comparisons with a constant (GH-143895) --- Include/internal/pycore_optimizer.h | 2 + Include/internal/pycore_optimizer_types.h | 14 ++ Lib/test/test_capi/test_opt.py | 40 +++++ Python/optimizer_analysis.c | 2 + Python/optimizer_bytecodes.c | 8 +- Python/optimizer_cases.c.h | 4 +- Python/optimizer_symbols.c | 191 ++++++++++++++++++++-- 7 files changed, 241 insertions(+), 20 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 0592221f152..fbe403b492d 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -205,6 +205,8 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value, extern bool _Py_uop_sym_is_compact_int(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx); extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym); +extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind); +extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true); extern void _Py_uop_abstractcontext_init(JitOptContext *ctx); extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx); diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index 6501ce869c1..7e0dbddce2d 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -40,6 +40,7 @@ typedef enum _JitSymType { JIT_SYM_TUPLE_TAG = 8, JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, + JIT_SYM_PREDICATE_TAG = 11, } JitSymType; typedef struct _jit_opt_known_class { @@ -72,6 +73,18 @@ typedef struct { uint16_t value; } JitOptTruthiness; +typedef enum { + JIT_PRED_IS, + JIT_PRED_IS_NOT, +} JitOptPredicateKind; + +typedef struct { + uint8_t tag; + uint8_t kind; + uint16_t lhs; + uint16_t rhs; +} JitOptPredicate; + typedef struct { uint8_t tag; } JitOptCompactInt; @@ -84,6 +97,7 @@ typedef union _jit_opt_symbol { JitOptTuple tuple; JitOptTruthiness truthiness; JitOptCompactInt compact; + JitOptPredicate predicate; } JitOptSymbol; // This mimics the _PyStackRef API diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 307eac6ee51..7c33320e9f1 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3551,6 +3551,46 @@ def test_is_none(n): self.assertIn("_POP_TOP_NOP", uops) self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_is_true_narrows_to_constant(self): + def f(n): + def return_true(): + return True + + hits = 0 + v = return_true() + for i in range(n): + if v is True: + hits += v + 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD * 2) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # v + 1 should be constant folded + self.assertNotIn("_BINARY_OP", uops) + + def test_is_false_narrows_to_constant(self): + def f(n): + def return_false(): + return False + + hits = 0 + v = return_false() + for i in range(n): + if v is False: + hits += v + 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # v + 1 should be constant folded + self.assertNotIn("_BINARY_OP", uops) + def test_for_iter_gen_frame(self): def f(n): for i in range(n): diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 01fd24564f8..e4e259a81b5 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -247,6 +247,8 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness +#define sym_new_predicate _Py_uop_sym_new_predicate +#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing #define JUMP_TO_LABEL(label) goto label; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 366094d939a..0ccc788dff9 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -38,6 +38,8 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness +#define sym_new_predicate _Py_uop_sym_new_predicate +#define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing extern int optimize_to_bool( @@ -533,7 +535,7 @@ dummy_func(void) { } op(_IS_OP, (left, right -- b, l, r)) { - b = sym_new_type(ctx, &PyBool_Type); + b = sym_new_predicate(ctx, left, right, (oparg ? JIT_PRED_IS_NOT : JIT_PRED_IS)); l = left; r = right; } @@ -1173,6 +1175,8 @@ dummy_func(void) { } op(_GUARD_IS_TRUE_POP, (flag -- )) { + sym_apply_predicate_narrowing(ctx, flag, true); + if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); assert(value != NULL); @@ -1191,6 +1195,8 @@ dummy_func(void) { } op(_GUARD_IS_FALSE_POP, (flag -- )) { + sym_apply_predicate_narrowing(ctx, flag, false); + if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); assert(value != NULL); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2cc53937925..f62e15b987c 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2293,7 +2293,7 @@ JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - b = sym_new_type(ctx, &PyBool_Type); + b = sym_new_predicate(ctx, left, right, (oparg ? JIT_PRED_IS_NOT : JIT_PRED_IS)); l = left; r = right; CHECK_STACK_BOUNDS(1); @@ -3715,6 +3715,7 @@ case _GUARD_IS_TRUE_POP: { JitOptRef flag; flag = stack_pointer[-1]; + sym_apply_predicate_narrowing(ctx, flag, true); if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); assert(value != NULL); @@ -3739,6 +3740,7 @@ case _GUARD_IS_FALSE_POP: { JitOptRef flag; flag = stack_pointer[-1]; + sym_apply_predicate_narrowing(ctx, flag, false); if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); assert(value != NULL); diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 5f5086d33b5..a9640aaa507 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -25,24 +25,24 @@ state represents no information, and the BOTTOM state represents contradictory information. Though symbols logically progress through all intermediate nodes, we often skip in-between states for convenience: - UNKNOWN - | | -NULL | -| | <- Anything below this level is an object. -| NON_NULL-+ -| | | <- Anything below this level has a known type version. -| TYPE_VERSION | -| | | <- Anything below this level has a known type. -| KNOWN_CLASS | -| | | | | | -| | | INT* | | -| | | | | | <- Anything below this level has a known truthiness. -| | | | | TRUTHINESS -| | | | | | -| TUPLE | | | | -| | | | | | <- Anything below this level is a known constant. -| KNOWN_VALUE--+ -| | <- Anything below this level is unreachable. + UNKNOWN-------------------+ + | | | +NULL | | +| | | <- Anything below this level is an object. +| NON_NULL-+ | +| | | | <- Anything below this level has a known type version. +| TYPE_VERSION | | +| | | | <- Anything below this level has a known type. +| KNOWN_CLASS | | +| | | | | | PREDICATE +| | | INT* | | | +| | | | | | | <- Anything below this level has a known truthiness. +| | | | | TRUTHINESS | +| | | | | | | +| TUPLE | | | | | +| | | | | | | <- Anything below this level is a known constant. +| KNOWN_VALUE--+----------+ +| | <- Anything below this level is unreachable. BOTTOM For example, after guarding that the type of an UNKNOWN local is int, we can @@ -309,6 +309,7 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ) sym->cls.version = 0; sym->cls.type = typ; return; + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: if (typ != &PyBool_Type) { sym_set_bottom(ctx, sym); @@ -370,6 +371,7 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver sym->tag = JIT_SYM_TYPE_VERSION_TAG; sym->version.version = version; return true; + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: if (version != PyBool_Type.tp_version_tag) { sym_set_bottom(ctx, sym); @@ -436,6 +438,13 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val) case JIT_SYM_UNKNOWN_TAG: make_const(sym, const_val); return; + case JIT_SYM_PREDICATE_TAG: + if (!PyBool_Check(const_val)) { + sym_set_bottom(ctx, sym); + return; + } + make_const(sym, const_val); + return; case JIT_SYM_TRUTHINESS_TAG: if (!PyBool_Check(const_val) || (_Py_uop_sym_is_const(ctx, ref) && @@ -589,6 +598,7 @@ _Py_uop_sym_get_type(JitOptRef ref) return _PyType_LookupByVersion(sym->version.version); case JIT_SYM_TUPLE_TAG: return &PyTuple_Type; + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: return &PyBool_Type; case JIT_SYM_COMPACT_INT: @@ -617,6 +627,7 @@ _Py_uop_sym_get_type_version(JitOptRef ref) return Py_TYPE(sym->value.value)->tp_version_tag; case JIT_SYM_TUPLE_TAG: return PyTuple_Type.tp_version_tag; + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: return PyBool_Type.tp_version_tag; case JIT_SYM_COMPACT_INT: @@ -810,6 +821,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) } return; case JIT_SYM_TUPLE_TAG: + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: sym_set_bottom(ctx, sym); return; @@ -823,6 +835,70 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) } } +JitOptRef +_Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind) +{ + JitOptSymbol *lhs = PyJitRef_Unwrap(lhs_ref); + JitOptSymbol *rhs = PyJitRef_Unwrap(rhs_ref); + + JitOptSymbol *res = sym_new(ctx); + if (res == NULL) { + return out_of_space_ref(ctx); + } + + res->tag = JIT_SYM_PREDICATE_TAG; + res->predicate.kind = kind; + res->predicate.lhs = (uint16_t)(lhs - allocation_base(ctx)); + res->predicate.rhs = (uint16_t)(rhs - allocation_base(ctx)); + + return PyJitRef_Wrap(res); +} + +void +_Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef ref, bool branch_is_true) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + if (sym->tag != JIT_SYM_PREDICATE_TAG) { + return; + } + + JitOptPredicate pred = sym->predicate; + + JitOptRef lhs_ref = PyJitRef_Wrap(allocation_base(ctx) + pred.lhs); + JitOptRef rhs_ref = PyJitRef_Wrap(allocation_base(ctx) + pred.rhs); + + bool lhs_is_const = _Py_uop_sym_is_const(ctx, lhs_ref); + bool rhs_is_const = _Py_uop_sym_is_const(ctx, rhs_ref); + if (!lhs_is_const && !rhs_is_const) { + return; + } + + bool narrow = false; + switch(pred.kind) { + case JIT_PRED_IS: + narrow = branch_is_true; + break; + case JIT_PRED_IS_NOT: + narrow = !branch_is_true; + break; + default: + return; + } + if (!narrow) { + return; + } + + JitOptRef subject_ref = lhs_is_const ? rhs_ref : lhs_ref; + JitOptRef const_ref = lhs_is_const ? lhs_ref : rhs_ref; + + PyObject *const_val = _Py_uop_sym_get_const(ctx, const_ref); + if (const_val == NULL) { + return; + } + _Py_uop_sym_set_const(ctx, subject_ref, const_val); + assert(_Py_uop_sym_is_const(ctx, subject_ref)); +} + JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef ref, bool truthy) { @@ -1159,6 +1235,85 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_is_const(ctx, value) == true, "value is not constant"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, value) == Py_True, "value is not True"); + // Resolving predicate result to True should narrow subject to True + JitOptRef subject = _Py_uop_sym_new_unknown(ctx); + JitOptRef const_true = _Py_uop_sym_new_const(ctx, Py_True); + if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_true)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_true, JIT_PRED_IS); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == Py_True, "predicate narrowing did not narrow subject to True"); + + // Resolving predicate result to False should not narrow subject + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_true, JIT_PRED_IS); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject"); + + // Resolving inverted predicate to False should narrow subject to True + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_true, JIT_PRED_IS_NOT); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing (inverted) did not const-narrow subject"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == Py_True, "predicate narrowing (inverted) did not narrow subject to True"); + + // Resolving inverted predicate to True should not narrow subject + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_true, JIT_PRED_IS_NOT); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to None + subject = _Py_uop_sym_new_unknown(ctx); + JitOptRef const_none = _Py_uop_sym_new_const(ctx, Py_None); + if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_none)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_none, JIT_PRED_IS); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (None)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == Py_None, "predicate narrowing did not narrow subject to None"); + + // Test narrowing subject to numerical constant + subject = _Py_uop_sym_new_unknown(ctx); + PyObject *one_obj = PyLong_FromLong(1); + JitOptRef const_one = _Py_uop_sym_new_const(ctx, one_obj); + if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_IS); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1"); val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66)); if (val_big == NULL) { From 3e66171efa3ca6b334931f6f9437d08065751352 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 22 Jan 2026 10:40:34 +0100 Subject: [PATCH 042/133] gh-142913: Revert adding test_replaced_interpreter (GH-144110) This partially reverts commit 4d5a676aa0811563ea78ae58ef89cdc0295bf7ed (GH-142911) The removed test fails when re-run in --huntrleaks mode. --- Lib/test/test_capi/test_misc.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index c9c757857a8..3997acbdf84 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -2857,24 +2857,6 @@ def func(): names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"] self.do_test(func, names) - def test_replaced_interpreter(self): - def inner(): - yield 'abc' - def outer(): - yield from inner() - def func(): - list(outer()) - _testinternalcapi.set_eval_frame_interp() - try: - func() - finally: - _testinternalcapi.set_eval_frame_default() - - stats = _testinternalcapi.get_eval_frame_stats() - - self.assertEqual(stats["resumes"], 5) - self.assertEqual(stats["loads"], 5) - @unittest.skipUnless(support.Py_GIL_DISABLED, 'need Py_GIL_DISABLED') class TestPyThreadId(unittest.TestCase): From 0b5f8359c52f8a5ce0fe436cde499553f3b8f5d5 Mon Sep 17 00:00:00 2001 From: Rafael Weingartner-Ortner <38643099+RafaelWO@users.noreply.github.com> Date: Thu, 22 Jan 2026 11:41:20 +0100 Subject: [PATCH 043/133] gh-143993: Document ways to disable remote debugging support (#143994) Although PEP 768 mentions how to disable the mechanism of remote debugging, it is not documented in the Python docs. This change adds a note on how to disable remote debugging support in a Python interpreter to the remote debugging how-to. Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/howto/remote_debugging.rst | 11 ++++++++++- Doc/library/sys.rst | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Doc/howto/remote_debugging.rst b/Doc/howto/remote_debugging.rst index 78b40bcdf71..dfe0176b75a 100644 --- a/Doc/howto/remote_debugging.rst +++ b/Doc/howto/remote_debugging.rst @@ -8,6 +8,16 @@ execute Python code remotely. Most platforms require elevated privileges to attach to another Python process. +Disabling remote debugging +-------------------------- + +To disable remote debugging support, use any of the following: + +* Set the :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` environment variable to ``1`` before + starting the interpreter. +* Use the :option:`-X disable_remote_debug` command-line option. +* Compile Python with the :option:`--without-remote-debug` build flag. + .. _permission-requirements: Permission requirements @@ -614,4 +624,3 @@ To inject and execute a Python script in a remote process: 6. Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field. 7. Resume the process (if suspended). The script will execute at the next safe evaluation point. - diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a0621d4b0db..f977f1389b6 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1997,6 +1997,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only interpreter is pre-release (alpha, beta, or release candidate) then the local and remote interpreters must be the same exact version. + See :ref:`remote-debugging` for more information about the remote debugging + mechanism. + .. audit-event:: sys.remote_exec pid script_path When the code is executed in the remote process, an @@ -2015,6 +2018,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only .. availability:: Unix, Windows. .. versionadded:: 3.14 + See :pep:`768` for more details. .. function:: _enablelegacywindowsfsencoding() From c447d1bc146bcf7707a619779bdcc03651adb5e3 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Thu, 22 Jan 2026 19:52:16 +0900 Subject: [PATCH 044/133] gh-143959: Make _datetime optional for test_sys (GH-144003) --- Lib/test/test_sys.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 1d8e908efb0..bdc0d75ba0c 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1,6 +1,5 @@ import builtins import codecs -import _datetime import gc import io import locale @@ -1742,7 +1741,12 @@ def delx(self): del self.__x x = property(getx, setx, delx, "") check(x, size('5Pi')) # PyCapsule - check(_datetime.datetime_CAPI, size('6P')) + try: + import _datetime + except ModuleNotFoundError: + pass + else: + check(_datetime.datetime_CAPI, size('6P')) # rangeiterator check(iter(range(1)), size('3l')) check(iter(range(2**65)), size('3P')) From fb690c38cafb15e4ccddc52aba37f9470ce201a0 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 22 Jan 2026 11:53:17 +0100 Subject: [PATCH 045/133] gh-141004: Mark up constants for `PyOS_double_to_string` (GH-143867) This ensures they show up as C macros in search and the Sphinx inventory. --- Doc/c-api/conversion.rst | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst index 96078d22710..f7c8ef8b22b 100644 --- a/Doc/c-api/conversion.rst +++ b/Doc/c-api/conversion.rst @@ -130,6 +130,8 @@ The following functions provide locale-independent string to number conversions. *flags* can be zero or more of the following values or-ed together: + .. c:namespace:: NULL + .. c:macro:: Py_DTSF_SIGN Always precede the returned string with a sign @@ -151,9 +153,21 @@ The following functions provide locale-independent string to number conversions. .. versionadded:: 3.11 - If *ptype* is non-``NULL``, then the value it points to will be set to one of - ``Py_DTST_FINITE``, ``Py_DTST_INFINITE``, or ``Py_DTST_NAN``, signifying that - *val* is a finite number, an infinite number, or not a number, respectively. + If *ptype* is non-``NULL``, then the value it points to will be set to one + of the following constants depending on the type of *val*: + + .. list-table:: + :header-rows: 1 + :align: left + + * - *\*ptype* + - type of *val* + * - .. c:macro:: Py_DTST_FINITE + - finite number + * - .. c:macro:: Py_DTST_INFINITE + - infinite number + * - .. c:macro:: Py_DTST_NAN + - not a number The return value is a pointer to *buffer* with the converted string or ``NULL`` if the conversion failed. The caller is responsible for freeing the From d77aaa73116aa469cc6b7a0f8a68f3f30fd41962 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 22 Jan 2026 10:55:49 +0000 Subject: [PATCH 046/133] GH-139109: Partial reworking of JIT data structures (GH-144105) * Halve size of buffers by reusing combined trace + optimizer buffers for TOS caching * Add simple buffer struct for more maintainable handling of buffers * Decouple JIT structs from thread state struct * Ensure terminator is added to trace, when optimizer gives up --- Include/internal/pycore_optimizer.h | 96 +++++++++- Include/internal/pycore_optimizer_types.h | 21 --- Include/internal/pycore_tstate.h | 43 +---- Include/internal/pycore_uop.h | 5 +- Python/ceval_macros.h | 2 +- Python/optimizer.c | 213 ++++++++++------------ Python/optimizer_analysis.c | 49 ++--- Python/optimizer_bytecodes.c | 7 +- Python/optimizer_cases.c.h | 6 +- Python/pystate.c | 1 - 10 files changed, 228 insertions(+), 215 deletions(-) diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index fbe403b492d..2ee518fb82f 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -16,12 +16,102 @@ extern "C" { #include +typedef struct _PyJitUopBuffer { + _PyUOpInstruction *start; + _PyUOpInstruction *next; + _PyUOpInstruction *end; +} _PyJitUopBuffer; + + +typedef struct _JitOptContext { + char done; + char out_of_space; + bool contradiction; + // Has the builtins dict been watched? + bool builtins_watched; + // The current "executing" frame. + _Py_UOpsAbstractFrame *frame; + _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; + int curr_frame_depth; + + // Arena for the symbolic types. + ty_arena t_arena; + + JitOptRef *n_consumed; + JitOptRef *limit; + JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; + _PyJitUopBuffer out_buffer; +} JitOptContext; + + +static inline void +uop_buffer_init(_PyJitUopBuffer *trace, _PyUOpInstruction *start, uint32_t size) +{ + trace->next = trace->start = start; + trace->end = start + size; +} + +static inline _PyUOpInstruction * +uop_buffer_last(_PyJitUopBuffer *trace) +{ + assert(trace->next > trace->start); + return trace->next-1; +} + +static inline int +uop_buffer_length(_PyJitUopBuffer *trace) +{ + return (int)(trace->next - trace->start); +} + +static inline int +uop_buffer_remaining_space(_PyJitUopBuffer *trace) +{ + return (int)(trace->end - trace->next); +} + +typedef struct _PyJitTracerInitialState { + int stack_depth; + int chain_depth; + struct _PyExitData *exit; + PyCodeObject *code; // Strong + PyFunctionObject *func; // Strong + struct _PyExecutorObject *executor; // Strong + _Py_CODEUNIT *start_instr; + _Py_CODEUNIT *close_loop_instr; + _Py_CODEUNIT *jump_backward_instr; +} _PyJitTracerInitialState; + +typedef struct _PyJitTracerPreviousState { + bool dependencies_still_valid; + int instr_oparg; + int instr_stacklevel; + _Py_CODEUNIT *instr; + PyCodeObject *instr_code; // Strong + struct _PyInterpreterFrame *instr_frame; + _PyBloomFilter dependencies; +} _PyJitTracerPreviousState; + +typedef struct _PyJitTracerTranslatorState { + int jump_backward_seen; +} _PyJitTracerTranslatorState; + +typedef struct _PyJitTracerState { + bool is_tracing; + _PyJitTracerInitialState initial_state; + _PyJitTracerPreviousState prev_state; + _PyJitTracerTranslatorState translator_state; + JitOptContext opt_context; + _PyJitUopBuffer code_buffer; + _PyJitUopBuffer out_buffer; + _PyUOpInstruction uop_array[2 * UOP_MAX_TRACE_LENGTH]; +} _PyJitTracerState; + typedef struct _PyExecutorLinkListNode { struct _PyExecutorObject *next; struct _PyExecutorObject *previous; } _PyExecutorLinkListNode; - typedef struct { uint8_t opcode; uint8_t oparg; @@ -86,8 +176,8 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp); int _Py_uop_analyze_and_optimize( _PyThreadStateImpl *tstate, - _PyUOpInstruction *trace, int trace_len, int curr_stackentries, - _PyBloomFilter *dependencies); + _PyUOpInstruction *input, int trace_len, int curr_stackentries, + _PyUOpInstruction *output, _PyBloomFilter *dependencies); extern PyTypeObject _PyUOpExecutor_Type; diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index 7e0dbddce2d..a879ca26ce7 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -126,27 +126,6 @@ typedef struct ty_arena { JitOptSymbol arena[TY_ARENA_SIZE]; } ty_arena; -typedef struct _JitOptContext { - char done; - char out_of_space; - bool contradiction; - // Has the builtins dict been watched? - bool builtins_watched; - // The current "executing" frame. - _Py_UOpsAbstractFrame *frame; - _Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH]; - int curr_frame_depth; - - // Arena for the symbolic types. - ty_arena t_arena; - - JitOptRef *n_consumed; - JitOptRef *limit; - JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; - _PyUOpInstruction *out_buffer; - int out_len; -} JitOptContext; - #ifdef __cplusplus } diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h index 24a40416c21..64b90710b8e 100644 --- a/Include/internal/pycore_tstate.h +++ b/Include/internal/pycore_tstate.h @@ -12,7 +12,6 @@ extern "C" { #include "pycore_freelist_state.h" // struct _Py_freelists #include "pycore_interpframe_structs.h" // _PyInterpreterFrame #include "pycore_mimalloc.h" // struct _mimalloc_thread_state -#include "pycore_optimizer_types.h" // JitOptContext #include "pycore_qsbr.h" // struct qsbr #include "pycore_uop.h" // struct _PyUOpInstruction #include "pycore_structs.h" @@ -24,46 +23,6 @@ struct _gc_thread_state { }; #endif -#if _Py_TIER2 -typedef struct _PyJitTracerInitialState { - int stack_depth; - int chain_depth; - struct _PyExitData *exit; - PyCodeObject *code; // Strong - PyFunctionObject *func; // Strong - struct _PyExecutorObject *executor; // Strong - _Py_CODEUNIT *start_instr; - _Py_CODEUNIT *close_loop_instr; - _Py_CODEUNIT *jump_backward_instr; -} _PyJitTracerInitialState; - -typedef struct _PyJitTracerPreviousState { - bool dependencies_still_valid; - int code_max_size; - int code_curr_size; - int instr_oparg; - int instr_stacklevel; - _Py_CODEUNIT *instr; - PyCodeObject *instr_code; // Strong - struct _PyInterpreterFrame *instr_frame; - _PyBloomFilter dependencies; -} _PyJitTracerPreviousState; - -typedef struct _PyJitTracerTranslatorState { - int jump_backward_seen; -} _PyJitTracerTranslatorState; - -typedef struct _PyJitTracerState { - bool is_tracing; - _PyJitTracerInitialState initial_state; - _PyJitTracerPreviousState prev_state; - _PyJitTracerTranslatorState translator_state; - JitOptContext opt_context; - _PyUOpInstruction code_buffer[UOP_MAX_TRACE_LENGTH]; - _PyUOpInstruction out_buffer[UOP_MAX_TRACE_LENGTH]; -} _PyJitTracerState; - -#endif // Every PyThreadState is actually allocated as a _PyThreadStateImpl. The // PyThreadState fields are exposed as part of the C API, although most fields @@ -141,7 +100,7 @@ typedef struct _PyThreadStateImpl { Py_ssize_t reftotal; // this thread's total refcount operations #endif #if _Py_TIER2 - _PyJitTracerState *jit_tracer_state; + struct _PyJitTracerState *jit_tracer_state; #endif } _PyThreadStateImpl; diff --git a/Include/internal/pycore_uop.h b/Include/internal/pycore_uop.h index e828a1cc5a5..f9be01acb57 100644 --- a/Include/internal/pycore_uop.h +++ b/Include/internal/pycore_uop.h @@ -38,11 +38,10 @@ typedef struct _PyUOpInstruction{ // This is the length of the trace we translate initially. #ifdef Py_DEBUG // With asserts, the stencils are a lot larger -#define UOP_MAX_TRACE_LENGTH 2000 +#define UOP_MAX_TRACE_LENGTH 1000 #else -#define UOP_MAX_TRACE_LENGTH 5000 +#define UOP_MAX_TRACE_LENGTH 2500 #endif -#define UOP_BUFFER_SIZE (UOP_MAX_TRACE_LENGTH * sizeof(_PyUOpInstruction)) /* Bloom filter with m = 256 * https://en.wikipedia.org/wiki/Bloom_filter */ diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 3b4b3253b36..d791ba0e8ec 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -433,7 +433,7 @@ do { \ JUMP_TO_LABEL(error); \ } \ if (keep_tracing_bit) { \ - assert(((_PyThreadStateImpl *)tstate)->jit_tracer_state->prev_state.code_curr_size == 2); \ + assert(uop_buffer_length(&((_PyThreadStateImpl *)tstate)->jit_tracer_state->code_buffer)); \ ENTER_TRACING(); \ DISPATCH_NON_TRACING(); \ } \ diff --git a/Python/optimizer.c b/Python/optimizer.c index 15a1eb5a177..f25242972ef 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -188,9 +188,6 @@ _PyOptimizer_Optimize( } insert_executor(code, start, index, executor); } - 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; @@ -547,52 +544,43 @@ guard_ip_uop[MAX_UOP_ID + 1] = { #endif -static inline int +static inline void add_to_trace( - _PyUOpInstruction *trace, - int trace_length, + _PyJitUopBuffer *trace, uint16_t opcode, uint16_t oparg, uint64_t operand, uint32_t target) { - trace[trace_length].opcode = opcode; - trace[trace_length].format = UOP_FORMAT_TARGET; - trace[trace_length].target = target; - trace[trace_length].oparg = oparg; - trace[trace_length].operand0 = operand; + _PyUOpInstruction *inst = trace->next; + inst->opcode = opcode; + inst->format = UOP_FORMAT_TARGET; + inst->target = target; + inst->oparg = oparg; + inst->operand0 = operand; #ifdef Py_STATS - trace[trace_length].execution_count = 0; + inst->execution_count = 0; #endif - return trace_length + 1; + trace->next++; } + #ifdef Py_DEBUG #define ADD_TO_TRACE(OPCODE, OPARG, OPERAND, TARGET) \ - assert(trace_length < max_length); \ - trace_length = add_to_trace(trace, trace_length, (OPCODE), (OPARG), (OPERAND), (TARGET)); \ + add_to_trace(trace, (OPCODE), (OPARG), (OPERAND), (TARGET)); \ if (lltrace >= 2) { \ - printf("%4d ADD_TO_TRACE: ", trace_length); \ - _PyUOpPrint(&trace[trace_length-1]); \ + printf("%4d ADD_TO_TRACE: ", uop_buffer_length(trace)); \ + _PyUOpPrint(uop_buffer_last(trace)); \ printf("\n"); \ } #else #define ADD_TO_TRACE(OPCODE, OPARG, OPERAND, TARGET) \ - assert(trace_length < max_length); \ - trace_length = add_to_trace(trace, trace_length, (OPCODE), (OPARG), (OPERAND), (TARGET)); + add_to_trace(trace, (OPCODE), (OPARG), (OPERAND), (TARGET)) #endif #define INSTR_IP(INSTR, CODE) \ ((uint32_t)((INSTR) - ((_Py_CODEUNIT *)(CODE)->co_code_adaptive))) -// Reserve space for n uops -#define RESERVE_RAW(n, opname) \ - if (trace_length + (n) > max_length) { \ - DPRINTF(2, "No room for %s (need %d, got %d)\n", \ - (opname), (n), max_length - trace_length); \ - OPT_STAT_INC(trace_too_long); \ - goto full; \ - } static int is_terminator(const _PyUOpInstruction *uop) @@ -629,9 +617,7 @@ _PyJit_translate_single_bytecode_to_trace( PyCodeObject *old_code = tracer->prev_state.instr_code; bool progress_needed = (tracer->initial_state.chain_depth % MAX_CHAIN_DEPTH) == 0; _PyBloomFilter *dependencies = &tracer->prev_state.dependencies; - int trace_length = tracer->prev_state.code_curr_size; - _PyUOpInstruction *trace = tracer->code_buffer; - int max_length = tracer->prev_state.code_max_size; + _PyJitUopBuffer *trace = &tracer->code_buffer; _Py_CODEUNIT *this_instr = tracer->prev_state.instr; _Py_CODEUNIT *target_instr = this_instr; @@ -670,15 +656,13 @@ _PyJit_translate_single_bytecode_to_trace( } } - int old_stack_level = tracer->prev_state.instr_stacklevel; - // Strange control-flow bool has_dynamic_jump_taken = OPCODE_HAS_UNPREDICTABLE_JUMP(opcode) && (next_instr != this_instr + 1 + _PyOpcode_Caches[_PyOpcode_Deopt[opcode]]); /* Special case the first instruction, * so that we can guarantee forward progress */ - if (progress_needed && tracer->prev_state.code_curr_size < CODE_SIZE_NO_PROGRESS) { + if (progress_needed && uop_buffer_length(&tracer->code_buffer) < CODE_SIZE_NO_PROGRESS) { if (OPCODE_HAS_EXIT(opcode) || OPCODE_HAS_DEOPT(opcode)) { opcode = _PyOpcode_Deopt[opcode]; } @@ -694,7 +678,7 @@ _PyJit_translate_single_bytecode_to_trace( int is_sys_tracing = (tstate->c_tracefunc != NULL) || (tstate->c_profilefunc != NULL); if (is_sys_tracing) { - goto full; + goto done; } if (stop_tracing_opcode == _DEOPT) { @@ -710,7 +694,7 @@ _PyJit_translate_single_bytecode_to_trace( goto done; } - DPRINTF(2, "%p %d: %s(%d) %d %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip, old_stack_level); + DPRINTF(2, "%p %d: %s(%d) %d\n", old_code, target, _PyOpcode_OpName[opcode], oparg, needs_guard_ip); #ifdef Py_DEBUG if (oparg > 255) { @@ -719,7 +703,7 @@ _PyJit_translate_single_bytecode_to_trace( #endif if (!tracer->prev_state.dependencies_still_valid) { - goto full; + goto done; } // This happens when a recursive call happens that we can't trace. Such as Python -> C -> Python calls @@ -734,16 +718,14 @@ _PyJit_translate_single_bytecode_to_trace( unsupported: { // Rewind to previous instruction and replace with _EXIT_TRACE. - _PyUOpInstruction *curr = &trace[trace_length-1]; - while (curr->opcode != _SET_IP && trace_length > 2) { - trace_length--; - curr = &trace[trace_length-1]; + _PyUOpInstruction *curr = uop_buffer_last(trace); + while (curr->opcode != _SET_IP && uop_buffer_length(trace) > 2) { + trace->next--; + curr = uop_buffer_last(trace); } - assert(curr->opcode == _SET_IP || trace_length == 2); + assert(curr->opcode == _SET_IP || uop_buffer_length(trace) == 2); if (curr->opcode == _SET_IP) { int32_t old_target = (int32_t)uop_get_target(curr); - curr++; - trace_length++; curr->opcode = _DEOPT; curr->format = UOP_FORMAT_TARGET; curr->target = old_target; @@ -752,7 +734,6 @@ _PyJit_translate_single_bytecode_to_trace( } } - if (opcode == NOP) { return 1; } @@ -766,7 +747,7 @@ _PyJit_translate_single_bytecode_to_trace( } // One for possible _DEOPT, one because _CHECK_VALIDITY itself might _DEOPT - max_length -= 2; + trace->end -= 2; const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -775,18 +756,28 @@ _PyJit_translate_single_bytecode_to_trace( if (OPCODE_HAS_EXIT(opcode)) { - // Make space for side exit and final _EXIT_TRACE: - max_length--; + // Make space for side exit + trace->end--; } if (OPCODE_HAS_ERROR(opcode)) { - // Make space for error stub and final _EXIT_TRACE: - max_length--; + // Make space for error stub + trace->end--; + } + if (OPCODE_HAS_DEOPT(opcode)) { + // Make space for side exit + trace->end--; } // _GUARD_IP leads to an exit. - max_length -= needs_guard_ip; + trace->end -= needs_guard_ip; - RESERVE_RAW(expansion->nuops + needs_guard_ip + 2 + (!OPCODE_HAS_NO_SAVE_IP(opcode)), "uop and various checks"); + int space_needed = expansion->nuops + needs_guard_ip + 2 + (!OPCODE_HAS_NO_SAVE_IP(opcode)); + if (uop_buffer_remaining_space(trace) < space_needed) { + DPRINTF(2, "No room for expansions and guards (need %d, got %d)\n", + space_needed, uop_buffer_remaining_space(trace)); + OPT_STAT_INC(trace_too_long); + goto done; + } ADD_TO_TRACE(_CHECK_VALIDITY, 0, 0, target); @@ -825,7 +816,7 @@ _PyJit_translate_single_bytecode_to_trace( { if ((next_instr != tracer->initial_state.close_loop_instr) && (next_instr != tracer->initial_state.start_instr) && - tracer->prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS && + uop_buffer_length(&tracer->code_buffer) > CODE_SIZE_NO_PROGRESS && // For side exits, we don't want to terminate them early. tracer->initial_state.exit == NULL && // These are coroutines, and we want to unroll those usually. @@ -836,7 +827,7 @@ _PyJit_translate_single_bytecode_to_trace( // inner loop might start and let the traces rejoin. OPT_STAT_INC(inner_loop); ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target); - trace[trace_length-1].operand1 = true; // is_control_flow + uop_buffer_last(trace)->operand1 = true; // is_control_flow DPRINTF(2, "JUMP_BACKWARD not to top ends trace %p %p %p\n", next_instr, tracer->initial_state.close_loop_instr, tracer->initial_state.start_instr); goto done; @@ -913,19 +904,19 @@ _PyJit_translate_single_bytecode_to_trace( } break; case OPERAND1_1: - assert(trace[trace_length-1].opcode == uop); + assert(uop_buffer_last(trace)->opcode == uop); operand = read_u16(&this_instr[offset].cache); - trace[trace_length-1].operand1 = operand; + uop_buffer_last(trace)->operand1 = operand; continue; case OPERAND1_2: - assert(trace[trace_length-1].opcode == uop); + assert(uop_buffer_last(trace)->opcode == uop); operand = read_u32(&this_instr[offset].cache); - trace[trace_length-1].operand1 = operand; + uop_buffer_last(trace)->operand1 = operand; continue; case OPERAND1_4: - assert(trace[trace_length-1].opcode == uop); + assert(uop_buffer_last(trace)->opcode == uop); operand = read_u64(&this_instr[offset].cache); - trace[trace_length-1].operand1 = operand; + uop_buffer_last(trace)->operand1 = operand; continue; default: fprintf(stderr, @@ -955,7 +946,7 @@ _PyJit_translate_single_bytecode_to_trace( } } ADD_TO_TRACE(uop, oparg, operand, target); - trace[trace_length - 1].operand1 = PyStackRef_IsNone(frame->f_executable) ? 2 : ((int)(frame->stackpointer - _PyFrame_Stackbase(frame))); + uop_buffer_last(trace)->operand1 = PyStackRef_IsNone(frame->f_executable) ? 2 : ((int)(frame->stackpointer - _PyFrame_Stackbase(frame))); break; } if (uop == _BINARY_OP_INPLACE_ADD_UNICODE) { @@ -973,9 +964,9 @@ _PyJit_translate_single_bytecode_to_trace( } // End switch (opcode) if (needs_guard_ip) { - uint16_t guard_ip = guard_ip_uop[trace[trace_length-1].opcode]; + uint16_t guard_ip = guard_ip_uop[uop_buffer_last(trace)->opcode]; if (guard_ip == 0) { - DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[trace[trace_length-1].opcode]); + DPRINTF(1, "Unknown uop needing guard ip %s\n", _PyOpcode_uop_name[uop_buffer_last(trace)->opcode]); Py_UNREACHABLE(); } ADD_TO_TRACE(guard_ip, 0, (uintptr_t)next_instr, 0); @@ -983,7 +974,7 @@ _PyJit_translate_single_bytecode_to_trace( // Loop back to the start int is_first_instr = tracer->initial_state.close_loop_instr == next_instr || tracer->initial_state.start_instr == next_instr; - if (is_first_instr && tracer->prev_state.code_curr_size > CODE_SIZE_NO_PROGRESS) { + if (is_first_instr && uop_buffer_length(trace) > CODE_SIZE_NO_PROGRESS) { if (needs_guard_ip) { ADD_TO_TRACE(_SET_IP, 0, (uintptr_t)next_instr, 0); } @@ -991,27 +982,13 @@ _PyJit_translate_single_bytecode_to_trace( goto done; } DPRINTF(2, "Trace continuing\n"); - tracer->prev_state.code_curr_size = trace_length; - tracer->prev_state.code_max_size = max_length; return 1; done: DPRINTF(2, "Trace done\n"); - tracer->prev_state.code_curr_size = trace_length; - tracer->prev_state.code_max_size = max_length; - return 0; -full: - DPRINTF(2, "Trace full\n"); - if (!is_terminator(&tracer->code_buffer[trace_length-1])) { - // Undo the last few instructions. - trace_length = tracer->prev_state.code_curr_size; - max_length = tracer->prev_state.code_max_size; - // We previously reversed one. - max_length += 1; + if (!is_terminator(uop_buffer_last(trace))) { ADD_TO_TRACE(_EXIT_TRACE, 0, 0, target); - trace[trace_length-1].operand1 = true; // is_control_flow + uop_buffer_last(trace)->operand1 = true; // is_control_flow } - tracer->prev_state.code_curr_size = trace_length; - tracer->prev_state.code_max_size = max_length; return 0; } @@ -1059,11 +1036,12 @@ _PyJit_TryInitializeTracing( 2 * INSTR_IP(close_loop_instr, code), chain_depth); #endif - add_to_trace(tracer->code_buffer, 0, _START_EXECUTOR, 0, (uintptr_t)start_instr, INSTR_IP(start_instr, code)); - add_to_trace(tracer->code_buffer, 1, _MAKE_WARM, 0, 0, 0); - tracer->prev_state.code_curr_size = CODE_SIZE_EMPTY; + /* Set up tracing buffer*/ + _PyJitUopBuffer *trace = &tracer->code_buffer; + uop_buffer_init(trace, &tracer->uop_array[0], UOP_MAX_TRACE_LENGTH); + ADD_TO_TRACE(_START_EXECUTOR, 0, (uintptr_t)start_instr, INSTR_IP(start_instr, code)); + ADD_TO_TRACE(_MAKE_WARM, 0, 0, 0); - tracer->prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2; tracer->initial_state.start_instr = start_instr; tracer->initial_state.close_loop_instr = close_loop_instr; tracer->initial_state.code = (PyCodeObject *)Py_NewRef(code); @@ -1122,8 +1100,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err) Py_CLEAR(tracer->initial_state.func); Py_CLEAR(tracer->initial_state.executor); Py_CLEAR(tracer->prev_state.instr_code); - tracer->prev_state.code_curr_size = CODE_SIZE_EMPTY; - tracer->prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2 - 1; + uop_buffer_init(&tracer->code_buffer, &tracer->uop_array[0], UOP_MAX_TRACE_LENGTH); tracer->is_tracing = false; } @@ -1137,7 +1114,6 @@ _PyJit_TracerFree(_PyThreadStateImpl *_tstate) } #undef RESERVE -#undef RESERVE_RAW #undef INSTR_IP #undef ADD_TO_TRACE #undef DPRINTF @@ -1467,39 +1443,47 @@ int effective_trace_length(_PyUOpInstruction *buffer, int length) static int -stack_allocate(_PyUOpInstruction *buffer, int length) +stack_allocate(_PyUOpInstruction *buffer, _PyUOpInstruction *output, int length) { assert(buffer[0].opcode == _START_EXECUTOR); - for (int i = length-1; i >= 0; i--) { - buffer[i*2+1] = buffer[i]; - buffer[i*2].format = UOP_FORMAT_TARGET; - buffer[i*2].oparg = 0; - buffer[i*2].target = 0; + /* The input buffer and output buffers will overlap. + Make sure that we can move instructions to the output + without overwriting the input. */ + if (buffer == output) { + // This can only happen if optimizer has not been run + for (int i = 0; i < length; i++) { + buffer[i + UOP_MAX_TRACE_LENGTH] = buffer[i]; + } + buffer += UOP_MAX_TRACE_LENGTH; + } + else { + assert(output + UOP_MAX_TRACE_LENGTH == buffer); } int depth = 0; + _PyUOpInstruction *write = output; for (int i = 0; i < length; i++) { - _PyUOpInstruction *spill_or_reload = &buffer[i*2]; - int uop = buffer[i*2+1].opcode; + int uop = buffer[i].opcode; if (uop == _NOP) { - // leave _NOPs to be cleaned up later - spill_or_reload->opcode = _NOP; continue; } int new_depth = _PyUop_Caching[uop].best[depth]; - if (new_depth == depth) { - spill_or_reload->opcode = _NOP; - } - else { - spill_or_reload->opcode = _PyUop_SpillsAndReloads[depth][new_depth]; + if (new_depth != depth) { + write->opcode = _PyUop_SpillsAndReloads[depth][new_depth]; + assert(write->opcode != 0); + write->format = UOP_FORMAT_TARGET; + write->oparg = 0; + write->target = 0; + write++; depth = new_depth; } + *write = buffer[i]; uint16_t new_opcode = _PyUop_Caching[uop].entries[depth].opcode; assert(new_opcode != 0); - assert(spill_or_reload->opcode != 0); - buffer[i*2+1].opcode = new_opcode; + write->opcode = new_opcode; + write++; depth = _PyUop_Caching[uop].entries[depth].output; } - return length*2; + return write - output; } static int @@ -1512,28 +1496,28 @@ uop_optimize( _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; assert(_tstate->jit_tracer_state != NULL); _PyBloomFilter *dependencies = &_tstate->jit_tracer_state->prev_state.dependencies; - _PyUOpInstruction *buffer = _tstate->jit_tracer_state->code_buffer; + _PyUOpInstruction *buffer = _tstate->jit_tracer_state->code_buffer.start; OPT_STAT_INC(attempts); bool is_noopt = !tstate->interp->opt_config.uops_optimize_enabled; int curr_stackentries = _tstate->jit_tracer_state->initial_state.stack_depth; - int length = _tstate->jit_tracer_state->prev_state.code_curr_size; + int length = uop_buffer_length(&_tstate->jit_tracer_state->code_buffer); if (length <= CODE_SIZE_NO_PROGRESS) { return 0; } assert(length > 0); - assert(length < UOP_MAX_TRACE_LENGTH/2); + assert(length < UOP_MAX_TRACE_LENGTH); OPT_STAT_INC(traces_created); if (!is_noopt) { + _PyUOpInstruction *output = &_tstate->jit_tracer_state->uop_array[UOP_MAX_TRACE_LENGTH]; length = _Py_uop_analyze_and_optimize( - _tstate, - buffer, length, - curr_stackentries, dependencies); + _tstate, buffer, length, curr_stackentries, + output, dependencies); if (length <= 0) { return length; } - buffer = _tstate->jit_tracer_state->out_buffer; + buffer = output; } - assert(length < UOP_MAX_TRACE_LENGTH/2); + assert(length < UOP_MAX_TRACE_LENGTH); assert(length >= 1); /* Fix up */ for (int pc = 0; pc < length; pc++) { @@ -1549,7 +1533,9 @@ uop_optimize( assert(_PyOpcode_uop_name[buffer[pc].opcode]); } OPT_HIST(effective_trace_length(buffer, length), optimized_trace_length_hist); - length = stack_allocate(buffer, length); + _PyUOpInstruction *output = &_tstate->jit_tracer_state->uop_array[0]; + length = stack_allocate(buffer, output, length); + buffer = output; length = prepare_for_execution(buffer, length); assert(length <= UOP_MAX_TRACE_LENGTH); _PyExecutorObject *executor = make_executor_from_uops( @@ -1707,6 +1693,7 @@ _Py_ExecutorInit(_PyExecutorObject *executor, const _PyBloomFilter *dependency_s { executor->vm_data.valid = true; executor->vm_data.pending_deletion = 0; + executor->vm_data.code = NULL; for (int i = 0; i < _Py_BLOOM_FILTER_WORDS; i++) { executor->vm_data.bloom.bits[i] = dependency_set->bits[i]; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index e4e259a81b5..c6a1ae60a31 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -203,14 +203,14 @@ static inline void add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, uint16_t opcode, uint16_t oparg, uintptr_t operand0) { - _PyUOpInstruction *out = &ctx->out_buffer[ctx->out_len]; + _PyUOpInstruction *out = ctx->out_buffer.next; out->opcode = (opcode); out->format = this_instr->format; out->oparg = (oparg); out->target = this_instr->target; out->operand0 = (operand0); out->operand1 = this_instr->operand1; - ctx->out_len++; + ctx->out_buffer.next++; } /* Shortened forms for convenience, used in optimizer_bytecodes.c */ @@ -430,6 +430,7 @@ optimize_uops( _PyUOpInstruction *trace, int trace_len, int curr_stacklen, + _PyUOpInstruction *output, _PyBloomFilter *dependencies ) { @@ -440,7 +441,7 @@ optimize_uops( JitOptContext *ctx = &tstate->jit_tracer_state->opt_context; uint32_t opcode = UINT16_MAX; - ctx->out_buffer = tstate->jit_tracer_state->out_buffer; + uop_buffer_init(&ctx->out_buffer, output, UOP_MAX_TRACE_LENGTH); // Make sure that watchers are set up PyInterpreterState *interp = _PyInterpreterState_GET(); @@ -458,14 +459,20 @@ optimize_uops( ctx->curr_frame_depth++; ctx->frame = frame; - ctx->out_len = 0; - _PyUOpInstruction *this_instr = NULL; JitOptRef *stack_pointer = ctx->frame->stack_pointer; - for (int i = 0; !ctx->done; i++) { - assert(i < trace_len); + for (int i = 0; i < trace_len; i++) { this_instr = &trace[i]; + if (ctx->done) { + // Don't do any more optimization, but + // we still need to reach a terminator for corrctness. + *(ctx->out_buffer.next++) = *this_instr; + if (is_terminator_uop(this_instr)) { + break; + } + continue; + } int oparg = this_instr->oparg; opcode = this_instr->opcode; @@ -485,6 +492,8 @@ optimize_uops( } #endif + _PyUOpInstruction *out_ptr = ctx->out_buffer.next; + switch (opcode) { #include "optimizer_cases.c.h" @@ -494,8 +503,8 @@ optimize_uops( Py_UNREACHABLE(); } // If no ADD_OP was called during this iteration, copy the original instruction - if (ctx->out_len == i) { - ctx->out_buffer[ctx->out_len++] = *this_instr; + if (ctx->out_buffer.next == out_ptr) { + *(ctx->out_buffer.next++) = *this_instr; } assert(ctx->frame != NULL); if (!CURRENT_FRAME_IS_INIT_SHIM()) { @@ -526,20 +535,11 @@ optimize_uops( * would be no benefit in retrying later */ _Py_uop_abstractcontext_fini(ctx); // Check that the trace ends with a proper terminator - if (ctx->out_len > 0) { - _PyUOpInstruction *last_uop = &ctx->out_buffer[ctx->out_len - 1]; - if (!is_terminator_uop(last_uop)) { - // Copy remaining uops from original trace until we find a terminator - for (int i = ctx->out_len; i < trace_len; i++) { - ctx->out_buffer[ctx->out_len++] = trace[i]; - if (is_terminator_uop(&trace[i])) { - break; - } - } - } + if (uop_buffer_length(&ctx->out_buffer) > 0) { + assert(is_terminator_uop(uop_buffer_last(&ctx->out_buffer))); } - return ctx->out_len; + return uop_buffer_length(&ctx->out_buffer); error: DPRINTF(3, "\n"); @@ -696,14 +696,15 @@ _Py_uop_analyze_and_optimize( _PyUOpInstruction *buffer, int length, int curr_stacklen, + _PyUOpInstruction *output, _PyBloomFilter *dependencies ) { OPT_STAT_INC(optimizer_attempts); length = optimize_uops( - tstate, buffer, - length, curr_stacklen, dependencies); + tstate, buffer, length, curr_stacklen, + output, dependencies); if (length == 0) { return length; @@ -711,7 +712,7 @@ _Py_uop_analyze_and_optimize( assert(length > 0); - length = remove_unneeded_uops(tstate->jit_tracer_state->out_buffer, length); + length = remove_unneeded_uops(output, length); assert(length > 0); OPT_STAT_INC(optimizer_successes); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 0ccc788dff9..1584e731d1b 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -194,7 +194,6 @@ dummy_func(void) { _Py_BloomFilter_Add(dependencies, type); } } - } } @@ -798,7 +797,7 @@ dummy_func(void) { if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) { assert(PyFunction_Check(sym_get_const(ctx, callable))); ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version); - ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)sym_get_const(ctx, callable); + uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)sym_get_const(ctx, callable); } sym_set_type(callable, &PyFunction_Type); } @@ -808,7 +807,7 @@ dummy_func(void) { PyMethodObject *method = (PyMethodObject *)sym_get_const(ctx, callable); assert(PyMethod_Check(method)); ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version); - ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)method->im_func; + uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)method->im_func; } sym_set_type(callable, &PyMethod_Type); } @@ -1570,7 +1569,7 @@ dummy_func(void) { ctx->frame->globals_watched = true; } if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) { - REPLACE_OP(&ctx->out_buffer[ctx->out_len - 1], _GUARD_GLOBALS_VERSION, 0, version); + REPLACE_OP(uop_buffer_last(&ctx->out_buffer), _GUARD_GLOBALS_VERSION, 0, version); ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index f62e15b987c..341805d51e2 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1557,7 +1557,7 @@ ctx->frame->globals_watched = true; } if (ctx->frame->globals_checked_version != version && this_instr[-1].opcode == _NOP) { - REPLACE_OP(&ctx->out_buffer[ctx->out_len - 1], _GUARD_GLOBALS_VERSION, 0, version); + REPLACE_OP(uop_buffer_last(&ctx->out_buffer), _GUARD_GLOBALS_VERSION, 0, version); ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { @@ -2861,7 +2861,7 @@ if (sym_is_const(ctx, callable) && sym_matches_type(callable, &PyFunction_Type)) { assert(PyFunction_Check(sym_get_const(ctx, callable))); ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version); - ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)sym_get_const(ctx, callable); + uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)sym_get_const(ctx, callable); } sym_set_type(callable, &PyFunction_Type); break; @@ -2879,7 +2879,7 @@ PyMethodObject *method = (PyMethodObject *)sym_get_const(ctx, callable); assert(PyMethod_Check(method)); ADD_OP(_CHECK_FUNCTION_VERSION_INLINE, 0, func_version); - ctx->out_buffer[ctx->out_len - 1].operand1 = (uintptr_t)method->im_func; + uop_buffer_last(&ctx->out_buffer)->operand1 = (uintptr_t)method->im_func; } sym_set_type(callable, &PyMethod_Type); break; diff --git a/Python/pystate.c b/Python/pystate.c index 89374e16722..19f1245d60a 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -24,7 +24,6 @@ #include "pycore_stackref.h" // Py_STACKREF_DEBUG #include "pycore_stats.h" // FT_STAT_WORLD_STOP_INC() #include "pycore_time.h" // _PyTime_Init() -#include "pycore_uop.h" // UOP_BUFFER_SIZE #include "pycore_uniqueid.h" // _PyObject_FinalizePerThreadRefcounts() From 67535ab2d26c83dd4658f67d35f072fc563c618f Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Thu, 22 Jan 2026 20:08:08 +0900 Subject: [PATCH 047/133] gh-143001: Add @cpython_only to test_sys.test_current_frames() (#144004) --- Lib/test/test_sys.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index bdc0d75ba0c..a5708b298c8 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -493,7 +493,7 @@ def test_getframemodulename(self): self.assertIs(f, f2) self.assertIsNone(sys._getframemodulename(i)) - # sys._current_frames() is a CPython-only gimmick. + @support.cpython_only # sys._current_frames() is a CPython-only gimmick. @threading_helper.reap_threads @threading_helper.requires_working_threading() def test_current_frames(self): From c5cfcdf16a98063530bdfe11a8894ab57aea3d92 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 22 Jan 2026 14:29:13 +0200 Subject: [PATCH 048/133] gh-67041: Allow to distinguish between empty and not defined URI components (GH-123305) Changes in the urllib.parse module: * Add option missing_as_none in urlparse(), urlsplit() and urldefrag(). If it is true, represent not defined components as None instead of an empty string. * Add option keep_empty in urlunparse() and urlunsplit(). If it is true, keep empty non-None components in the resulting string. --- Doc/library/urllib.parse.rst | 212 ++++--- Doc/whatsnew/3.15.rst | 12 + Lib/test/test_urlparse.py | 576 ++++++++++++------ Lib/urllib/parse.py | 250 ++++++-- Mac/Resources/app-store-compliance.patch | 20 +- ...4-11-27-13-11-16.gh-issue-67041.ym2WKK.rst | 6 + 6 files changed, 754 insertions(+), 322 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-11-27-13-11-16.gh-issue-67041.ym2WKK.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 44a9c79cba2..ba6e46858f9 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -50,12 +50,16 @@ URL Parsing The URL parsing functions focus on splitting a URL string into its components, or on combining URL components into a URL string. -.. function:: urlparse(urlstring, scheme='', allow_fragments=True) +.. function:: urlparse(urlstring, scheme=None, allow_fragments=True, *, missing_as_none=False) Parse a URL into six components, returning a 6-item :term:`named tuple`. This corresponds to the general structure of a URL: ``scheme://netloc/path;parameters?query#fragment``. - Each tuple item is a string, possibly empty. The components are not broken up + Each tuple item is a string, possibly empty, or ``None`` if + *missing_as_none* is true. + Not defined component are represented an empty string (by default) or + ``None`` if *missing_as_none* is true. + The components are not broken up into smaller parts (for example, the network location is a single string), and % escapes are not expanded. The delimiters as shown above are not part of the result, except for a leading slash in the *path* component, which is retained if @@ -84,6 +88,12 @@ or on combining URL components into a URL string. 80 >>> o._replace(fragment="").geturl() 'http://docs.python.org:80/3/library/urllib.parse.html?highlight=params' + >>> urlparse("http://docs.python.org?") + ParseResult(scheme='http', netloc='docs.python.org', + path='', params='', query='', fragment='') + >>> urlparse("http://docs.python.org?", missing_as_none=True) + ParseResult(scheme='http', netloc='docs.python.org', + path='', params=None, query='', fragment=None) Following the syntax specifications in :rfc:`1808`, urlparse recognizes a netloc only if it is properly introduced by '//'. Otherwise the @@ -101,47 +111,53 @@ or on combining URL components into a URL string. ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html', params='', query='', fragment='') >>> urlparse('help/Python.html') - ParseResult(scheme='', netloc='', path='help/Python.html', params='', - query='', fragment='') + ParseResult(scheme='', netloc='', path='help/Python.html', + params='', query='', fragment='') + >>> urlparse('help/Python.html', missing_as_none=True) + ParseResult(scheme=None, netloc=None, path='help/Python.html', + params=None, query=None, fragment=None) The *scheme* argument gives the default addressing scheme, to be used only if the URL does not specify one. It should be the same type - (text or bytes) as *urlstring*, except that the default value ``''`` is + (text or bytes) as *urlstring* or ``None``, except that the ``''`` is always allowed, and is automatically converted to ``b''`` if appropriate. If the *allow_fragments* argument is false, fragment identifiers are not recognized. Instead, they are parsed as part of the path, parameters - or query component, and :attr:`fragment` is set to the empty string in - the return value. + or query component, and :attr:`fragment` is set to ``None`` or the empty + string (depending on the value of *missing_as_none*) in the return value. The return value is a :term:`named tuple`, which means that its items can be accessed by index or as named attributes, which are: - +------------------+-------+-------------------------+------------------------+ - | Attribute | Index | Value | Value if not present | - +==================+=======+=========================+========================+ - | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter | - +------------------+-------+-------------------------+------------------------+ - | :attr:`netloc` | 1 | Network location part | empty string | - +------------------+-------+-------------------------+------------------------+ - | :attr:`path` | 2 | Hierarchical path | empty string | - +------------------+-------+-------------------------+------------------------+ - | :attr:`params` | 3 | Parameters for last | empty string | - | | | path element | | - +------------------+-------+-------------------------+------------------------+ - | :attr:`query` | 4 | Query component | empty string | - +------------------+-------+-------------------------+------------------------+ - | :attr:`fragment` | 5 | Fragment identifier | empty string | - +------------------+-------+-------------------------+------------------------+ - | :attr:`username` | | User name | :const:`None` | - +------------------+-------+-------------------------+------------------------+ - | :attr:`password` | | Password | :const:`None` | - +------------------+-------+-------------------------+------------------------+ - | :attr:`hostname` | | Host name (lower case) | :const:`None` | - +------------------+-------+-------------------------+------------------------+ - | :attr:`port` | | Port number as integer, | :const:`None` | - | | | if present | | - +------------------+-------+-------------------------+------------------------+ + +------------------+-------+-------------------------+-------------------------------+ + | Attribute | Index | Value | Value if not present | + +==================+=======+=========================+===============================+ + | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter or | + | | | | empty string [1]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`netloc` | 1 | Network location part | ``None`` or empty string [1]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`path` | 2 | Hierarchical path | empty string | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`params` | 3 | Parameters for last | ``None`` or empty string [1]_ | + | | | path element | | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`query` | 4 | Query component | ``None`` or empty string [1]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`fragment` | 5 | Fragment identifier | ``None`` or empty string [1]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`username` | | User name | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`password` | | Password | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`hostname` | | Host name (lower case) | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`port` | | Port number as integer, | ``None`` | + | | | if present | | + +------------------+-------+-------------------------+-------------------------------+ + + .. [1] Depending on the value of the *missing_as_none* argument. Reading the :attr:`port` attribute will raise a :exc:`ValueError` if an invalid port is specified in the URL. See section @@ -187,12 +203,15 @@ or on combining URL components into a URL string. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of - returning :const:`None`. + returning ``None``. .. versionchanged:: 3.8 Characters that affect netloc parsing under NFKC normalization will now raise :exc:`ValueError`. + .. versionchanged:: next + Added the *missing_as_none* parameter. + .. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&') @@ -288,15 +307,27 @@ or on combining URL components into a URL string. .. function:: urlunparse(parts) + urlunparse(parts, *, keep_empty) Construct a URL from a tuple as returned by ``urlparse()``. The *parts* - argument can be any six-item iterable. This may result in a slightly - different, but equivalent URL, if the URL that was parsed originally had - unnecessary delimiters (for example, a ``?`` with an empty query; the RFC - states that these are equivalent). + argument can be any six-item iterable. + + This may result in a slightly different, but equivalent URL, if the + URL that was parsed originally had unnecessary delimiters (for example, + a ``?`` with an empty query; the RFC states that these are equivalent). + + If *keep_empty* is true, empty strings are kept in the result (for example, + a ``?`` for an empty query), only ``None`` components are omitted. + This allows rebuilding a URL that was parsed with option + ``missing_as_none=True``. + By default, *keep_empty* is true if *parts* is the result of the + :func:`urlparse` call with ``missing_as_none=True``. + + .. versionchanged:: next + Added the *keep_empty* parameter. -.. function:: urlsplit(urlstring, scheme='', allow_fragments=True) +.. function:: urlsplit(urlstring, scheme=None, allow_fragments=True, *, missing_as_none=False) This is similar to :func:`urlparse`, but does not split the params from the URL. This should generally be used instead of :func:`urlparse` if the more recent URL @@ -310,28 +341,31 @@ or on combining URL components into a URL string. The return value is a :term:`named tuple`, its items can be accessed by index or as named attributes: - +------------------+-------+-------------------------+----------------------+ - | Attribute | Index | Value | Value if not present | - +==================+=======+=========================+======================+ - | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter | - +------------------+-------+-------------------------+----------------------+ - | :attr:`netloc` | 1 | Network location part | empty string | - +------------------+-------+-------------------------+----------------------+ - | :attr:`path` | 2 | Hierarchical path | empty string | - +------------------+-------+-------------------------+----------------------+ - | :attr:`query` | 3 | Query component | empty string | - +------------------+-------+-------------------------+----------------------+ - | :attr:`fragment` | 4 | Fragment identifier | empty string | - +------------------+-------+-------------------------+----------------------+ - | :attr:`username` | | User name | :const:`None` | - +------------------+-------+-------------------------+----------------------+ - | :attr:`password` | | Password | :const:`None` | - +------------------+-------+-------------------------+----------------------+ - | :attr:`hostname` | | Host name (lower case) | :const:`None` | - +------------------+-------+-------------------------+----------------------+ - | :attr:`port` | | Port number as integer, | :const:`None` | - | | | if present | | - +------------------+-------+-------------------------+----------------------+ + +------------------+-------+-------------------------+-------------------------------+ + | Attribute | Index | Value | Value if not present | + +==================+=======+=========================+===============================+ + | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter or | + | | | | empty string [1]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`netloc` | 1 | Network location part | ``None`` or empty string [2]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`path` | 2 | Hierarchical path | empty string | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`query` | 3 | Query component | ``None`` or empty string [2]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`fragment` | 4 | Fragment identifier | ``None`` or empty string [2]_ | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`username` | | User name | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`password` | | Password | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`hostname` | | Host name (lower case) | ``None`` | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`port` | | Port number as integer, | ``None`` | + | | | if present | | + +------------------+-------+-------------------------+-------------------------------+ + + .. [2] Depending on the value of the *missing_as_none* argument. Reading the :attr:`port` attribute will raise a :exc:`ValueError` if an invalid port is specified in the URL. See section @@ -356,7 +390,7 @@ or on combining URL components into a URL string. .. versionchanged:: 3.6 Out-of-range port numbers now raise :exc:`ValueError`, instead of - returning :const:`None`. + returning ``None``. .. versionchanged:: 3.8 Characters that affect netloc parsing under NFKC normalization will @@ -368,15 +402,31 @@ or on combining URL components into a URL string. .. versionchanged:: 3.12 Leading WHATWG C0 control and space characters are stripped from the URL. + .. versionchanged:: next + Added the *missing_as_none* parameter. + .. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser .. function:: urlunsplit(parts) + urlunsplit(parts, *, keep_empty) Combine the elements of a tuple as returned by :func:`urlsplit` into a complete URL as a string. The *parts* argument can be any five-item - iterable. This may result in a slightly different, but equivalent URL, if the - URL that was parsed originally had unnecessary delimiters (for example, a ? - with an empty query; the RFC states that these are equivalent). + iterable. + + This may result in a slightly different, but equivalent URL, if the + URL that was parsed originally had unnecessary delimiters (for example, + a ``?`` with an empty query; the RFC states that these are equivalent). + + If *keep_empty* is true, empty strings are kept in the result (for example, + a ``?`` for an empty query), only ``None`` components are omitted. + This allows rebuilding a URL that was parsed with option + ``missing_as_none=True``. + By default, *keep_empty* is true if *parts* is the result of the + :func:`urlsplit` call with ``missing_as_none=True``. + + .. versionchanged:: next + Added the *keep_empty* parameter. .. function:: urljoin(base, url, allow_fragments=True) @@ -422,23 +472,25 @@ or on combining URL components into a URL string. Behavior updated to match the semantics defined in :rfc:`3986`. -.. function:: urldefrag(url) +.. function:: urldefrag(url, *, missing_as_none=False) If *url* contains a fragment identifier, return a modified version of *url* with no fragment identifier, and the fragment identifier as a separate string. If there is no fragment identifier in *url*, return *url* unmodified - and an empty string. + and an empty string (by default) or ``None`` if *missing_as_none* is true. The return value is a :term:`named tuple`, its items can be accessed by index or as named attributes: - +------------------+-------+-------------------------+----------------------+ - | Attribute | Index | Value | Value if not present | - +==================+=======+=========================+======================+ - | :attr:`url` | 0 | URL with no fragment | empty string | - +------------------+-------+-------------------------+----------------------+ - | :attr:`fragment` | 1 | Fragment identifier | empty string | - +------------------+-------+-------------------------+----------------------+ + +------------------+-------+-------------------------+-------------------------------+ + | Attribute | Index | Value | Value if not present | + +==================+=======+=========================+===============================+ + | :attr:`url` | 0 | URL with no fragment | empty string | + +------------------+-------+-------------------------+-------------------------------+ + | :attr:`fragment` | 1 | Fragment identifier | ``None`` or empty string [3]_ | + +------------------+-------+-------------------------+-------------------------------+ + + .. [3] Depending on the value of the *missing_as_none* argument. See section :ref:`urlparse-result-object` for more information on the result object. @@ -446,6 +498,9 @@ or on combining URL components into a URL string. .. versionchanged:: 3.2 Result is a structured object rather than a simple 2-tuple. + .. versionchanged:: next + Added the *missing_as_none* parameter. + .. function:: unwrap(url) Extract the url from a wrapped URL (that is, a string formatted as @@ -465,8 +520,9 @@ URLs elsewhere. Their purpose is for practical functionality rather than purity. Instead of raising an exception on unusual input, they may instead return some -component parts as empty strings. Or components may contain more than perhaps -they should. +component parts as empty strings or ``None`` (depending on the value of the +*missing_as_none* argument). +Or components may contain more than perhaps they should. We recommend that users of these APIs where the values may be used anywhere with security implications code defensively. Do some verification within your @@ -542,7 +598,8 @@ previous section, as well as an additional method: Return the re-combined version of the original URL as a string. This may differ from the original URL in that the scheme may be normalized to lower case and empty components may be dropped. Specifically, empty parameters, - queries, and fragment identifiers will be removed. + queries, and fragment identifiers will be removed unless the URL was parsed + with ``missing_as_none=True``. For :func:`urldefrag` results, only empty fragment identifiers will be removed. For :func:`urlsplit` and :func:`urlparse` results, all noted changes will be @@ -559,6 +616,9 @@ previous section, as well as an additional method: >>> r2 = urlsplit(r1.geturl()) >>> r2.geturl() 'http://www.Python.org/doc/' + >>> r3 = urlsplit(url, missing_as_none=True) + >>> r3.geturl() + 'http://www.Python.org/doc/#' The following classes provide the implementations of the structured parse diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 1d4961d7293..8c92ac8e031 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -836,6 +836,18 @@ unittest (Contributed by Garry Cairns in :gh:`134567`.) +urllib.parse +------------ + +* Add the *missing_as_none* parameter to :func:`~urllib.parse.urlparse`, + :func:`~urllib.parse.urlsplit` and :func:`~urllib.parse.urldefrag` functions. + Add the *keep_empty* parameter to :func:`~urllib.parse.urlunparse` and + :func:`~urllib.parse.urlunsplit` functions. + This allows to distinguish between empty and not defined URI components + and preserve empty components. + (Contributed by Serhiy Storchaka in :gh:`67041`.) + + venv ---- diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py index b2bde5a9b1d..49a292df934 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py @@ -1,7 +1,10 @@ +import copy +import pickle import sys import unicodedata import unittest import urllib.parse +from urllib.parse import urldefrag, urlparse, urlsplit, urlunparse, urlunsplit from test import support RFC1808_BASE = "http://a/b/c/d;p?q#f" @@ -107,19 +110,46 @@ class UrlParseTestCase(unittest.TestCase): def checkRoundtrips(self, url, parsed, split, url2=None): if url2 is None: url2 = url - result = urllib.parse.urlparse(url) + self.checkRoundtrips1(url, parsed, split, missing_as_none=True) + empty = url[:0] + parsed = tuple(x or empty for x in parsed) + split = tuple(x or empty for x in split) + self.checkRoundtrips1(url, parsed, split, url2, missing_as_none=False) + + result = urlparse(url, missing_as_none=True) + self.assertEqual(urlunparse(result, keep_empty=False), url2) + self.assertEqual(urlunparse(tuple(result), keep_empty=False), url2) + result = urlparse(url, missing_as_none=False) + with self.assertRaises(ValueError): + urlunparse(result, keep_empty=True) + urlunparse(tuple(result), keep_empty=True) + + result = urlsplit(url, missing_as_none=True) + self.assertEqual(urlunsplit(result, keep_empty=False), url2) + self.assertEqual(urlunsplit(tuple(result), keep_empty=False), url2) + result = urlsplit(url, missing_as_none=False) + with self.assertRaises(ValueError): + urlunsplit(result, keep_empty=True) + urlunsplit(tuple(result), keep_empty=True) + + def checkRoundtrips1(self, url, parsed, split, url2=None, *, missing_as_none): + if url2 is None: + url2 = url + result = urlparse(url, missing_as_none=missing_as_none) self.assertSequenceEqual(result, parsed) t = (result.scheme, result.netloc, result.path, result.params, result.query, result.fragment) self.assertSequenceEqual(t, parsed) # put it back together and it should be the same - result2 = urllib.parse.urlunparse(result) - self.assertSequenceEqual(result2, url2) - self.assertSequenceEqual(result2, result.geturl()) + result2 = urlunparse(result) + self.assertEqual(result2, url2) + self.assertEqual(result2, result.geturl()) + self.assertEqual(urlunparse(result, keep_empty=missing_as_none), url2) + self.assertEqual(urlunparse(tuple(result), keep_empty=missing_as_none), result2) # the result of geturl() is a fixpoint; we can always parse it # again to get the same result: - result3 = urllib.parse.urlparse(result.geturl()) + result3 = urlparse(result.geturl(), missing_as_none=missing_as_none) self.assertEqual(result3.geturl(), result.geturl()) self.assertSequenceEqual(result3, result) self.assertEqual(result3.scheme, result.scheme) @@ -134,17 +164,18 @@ def checkRoundtrips(self, url, parsed, split, url2=None): self.assertEqual(result3.port, result.port) # check the roundtrip using urlsplit() as well - result = urllib.parse.urlsplit(url) + result = urlsplit(url, missing_as_none=missing_as_none) self.assertSequenceEqual(result, split) t = (result.scheme, result.netloc, result.path, - result.query, result.fragment) + result.query, result.fragment) self.assertSequenceEqual(t, split) - result2 = urllib.parse.urlunsplit(result) - self.assertSequenceEqual(result2, url2) - self.assertSequenceEqual(result2, result.geturl()) + result2 = urlunsplit(result) + self.assertEqual(result2, url2) + self.assertEqual(result2, result.geturl()) + self.assertEqual(urlunsplit(tuple(result), keep_empty=missing_as_none), result2) # check the fixpoint property of re-parsing the result of geturl() - result3 = urllib.parse.urlsplit(result.geturl()) + result3 = urlsplit(result.geturl(), missing_as_none=missing_as_none) self.assertEqual(result3.geturl(), result.geturl()) self.assertSequenceEqual(result3, result) self.assertEqual(result3.scheme, result.scheme) @@ -177,94 +208,94 @@ def test_qs(self, orig, expect): @support.subTests('bytes', (False, True)) @support.subTests('url,parsed,split', [ ('path/to/file', - ('', '', 'path/to/file', '', '', ''), - ('', '', 'path/to/file', '', '')), + (None, None, 'path/to/file', None, None, None), + (None, None, 'path/to/file', None, None)), ('/path/to/file', - ('', '', '/path/to/file', '', '', ''), - ('', '', '/path/to/file', '', '')), + (None, None, '/path/to/file', None, None, None), + (None, None, '/path/to/file', None, None)), ('//path/to/file', - ('', 'path', '/to/file', '', '', ''), - ('', 'path', '/to/file', '', '')), + (None, 'path', '/to/file', None, None, None), + (None, 'path', '/to/file', None, None)), ('////path/to/file', - ('', '', '//path/to/file', '', '', ''), - ('', '', '//path/to/file', '', '')), + (None, '', '//path/to/file', None, None, None), + (None, '', '//path/to/file', None, None)), ('/////path/to/file', - ('', '', '///path/to/file', '', '', ''), - ('', '', '///path/to/file', '', '')), + (None, '', '///path/to/file', None, None, None), + (None, '', '///path/to/file', None, None)), ('scheme:path/to/file', - ('scheme', '', 'path/to/file', '', '', ''), - ('scheme', '', 'path/to/file', '', '')), + ('scheme', None, 'path/to/file', None, None, None), + ('scheme', None, 'path/to/file', None, None)), ('scheme:/path/to/file', - ('scheme', '', '/path/to/file', '', '', ''), - ('scheme', '', '/path/to/file', '', '')), + ('scheme', None, '/path/to/file', None, None, None), + ('scheme', None, '/path/to/file', None, None)), ('scheme://path/to/file', - ('scheme', 'path', '/to/file', '', '', ''), - ('scheme', 'path', '/to/file', '', '')), + ('scheme', 'path', '/to/file', None, None, None), + ('scheme', 'path', '/to/file', None, None)), ('scheme:////path/to/file', - ('scheme', '', '//path/to/file', '', '', ''), - ('scheme', '', '//path/to/file', '', '')), + ('scheme', '', '//path/to/file', None, None, None), + ('scheme', '', '//path/to/file', None, None)), ('scheme://///path/to/file', - ('scheme', '', '///path/to/file', '', '', ''), - ('scheme', '', '///path/to/file', '', '')), + ('scheme', '', '///path/to/file', None, None, None), + ('scheme', '', '///path/to/file', None, None)), ('file:tmp/junk.txt', - ('file', '', 'tmp/junk.txt', '', '', ''), - ('file', '', 'tmp/junk.txt', '', '')), + ('file', None, 'tmp/junk.txt', None, None, None), + ('file', None, 'tmp/junk.txt', None, None)), ('file:///tmp/junk.txt', - ('file', '', '/tmp/junk.txt', '', '', ''), - ('file', '', '/tmp/junk.txt', '', '')), + ('file', '', '/tmp/junk.txt', None, None, None), + ('file', '', '/tmp/junk.txt', None, None)), ('file:////tmp/junk.txt', - ('file', '', '//tmp/junk.txt', '', '', ''), - ('file', '', '//tmp/junk.txt', '', '')), + ('file', '', '//tmp/junk.txt', None, None, None), + ('file', '', '//tmp/junk.txt', None, None)), ('file://///tmp/junk.txt', - ('file', '', '///tmp/junk.txt', '', '', ''), - ('file', '', '///tmp/junk.txt', '', '')), + ('file', '', '///tmp/junk.txt', None, None, None), + ('file', '', '///tmp/junk.txt', None, None)), ('http:tmp/junk.txt', - ('http', '', 'tmp/junk.txt', '', '', ''), - ('http', '', 'tmp/junk.txt', '', '')), + ('http', None, 'tmp/junk.txt', None, None, None), + ('http', None, 'tmp/junk.txt', None, None)), ('http://example.com/tmp/junk.txt', - ('http', 'example.com', '/tmp/junk.txt', '', '', ''), - ('http', 'example.com', '/tmp/junk.txt', '', '')), + ('http', 'example.com', '/tmp/junk.txt', None, None, None), + ('http', 'example.com', '/tmp/junk.txt', None, None)), ('http:///example.com/tmp/junk.txt', - ('http', '', '/example.com/tmp/junk.txt', '', '', ''), - ('http', '', '/example.com/tmp/junk.txt', '', '')), + ('http', '', '/example.com/tmp/junk.txt', None, None, None), + ('http', '', '/example.com/tmp/junk.txt', None, None)), ('http:////example.com/tmp/junk.txt', - ('http', '', '//example.com/tmp/junk.txt', '', '', ''), - ('http', '', '//example.com/tmp/junk.txt', '', '')), + ('http', '', '//example.com/tmp/junk.txt', None, None, None), + ('http', '', '//example.com/tmp/junk.txt', None, None)), ('imap://mail.python.org/mbox1', - ('imap', 'mail.python.org', '/mbox1', '', '', ''), - ('imap', 'mail.python.org', '/mbox1', '', '')), + ('imap', 'mail.python.org', '/mbox1', None, None, None), + ('imap', 'mail.python.org', '/mbox1', None, None)), ('mms://wms.sys.hinet.net/cts/Drama/09006251100.asf', ('mms', 'wms.sys.hinet.net', '/cts/Drama/09006251100.asf', - '', '', ''), + None, None, None), ('mms', 'wms.sys.hinet.net', '/cts/Drama/09006251100.asf', - '', '')), + None, None)), ('nfs://server/path/to/file.txt', - ('nfs', 'server', '/path/to/file.txt', '', '', ''), - ('nfs', 'server', '/path/to/file.txt', '', '')), + ('nfs', 'server', '/path/to/file.txt', None, None, None), + ('nfs', 'server', '/path/to/file.txt', None, None)), ('svn+ssh://svn.zope.org/repos/main/ZConfig/trunk/', ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/', - '', '', ''), + None, None, None), ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/', - '', '')), + None, None)), ('git+ssh://git@github.com/user/project.git', ('git+ssh', 'git@github.com','/user/project.git', - '','',''), + None,None,None), ('git+ssh', 'git@github.com','/user/project.git', - '', '')), + None, None)), ('itms-services://?action=download-manifest&url=https://example.com/app', - ('itms-services', '', '', '', - 'action=download-manifest&url=https://example.com/app', ''), + ('itms-services', '', '', None, + 'action=download-manifest&url=https://example.com/app', None), ('itms-services', '', '', - 'action=download-manifest&url=https://example.com/app', '')), + 'action=download-manifest&url=https://example.com/app', None)), ('+scheme:path/to/file', - ('', '', '+scheme:path/to/file', '', '', ''), - ('', '', '+scheme:path/to/file', '', '')), + (None, None, '+scheme:path/to/file', None, None, None), + (None, None, '+scheme:path/to/file', None, None)), ('sch_me:path/to/file', - ('', '', 'sch_me:path/to/file', '', '', ''), - ('', '', 'sch_me:path/to/file', '', '')), + (None, None, 'sch_me:path/to/file', None, None, None), + (None, None, 'sch_me:path/to/file', None, None)), ('schème:path/to/file', - ('', '', 'schème:path/to/file', '', '', ''), - ('', '', 'schème:path/to/file', '', '')), + (None, None, 'schème:path/to/file', None, None, None), + (None, None, 'schème:path/to/file', None, None)), ]) def test_roundtrips(self, bytes, url, parsed, split): if bytes: @@ -279,24 +310,24 @@ def test_roundtrips(self, bytes, url, parsed, split): @support.subTests('url,url2,parsed,split', [ ('///path/to/file', '/path/to/file', - ('', '', '/path/to/file', '', '', ''), - ('', '', '/path/to/file', '', '')), + (None, '', '/path/to/file', None, None, None), + (None, '', '/path/to/file', None, None)), ('scheme:///path/to/file', 'scheme:/path/to/file', - ('scheme', '', '/path/to/file', '', '', ''), - ('scheme', '', '/path/to/file', '', '')), + ('scheme', '', '/path/to/file', None, None, None), + ('scheme', '', '/path/to/file', None, None)), ('file:/tmp/junk.txt', 'file:///tmp/junk.txt', - ('file', '', '/tmp/junk.txt', '', '', ''), - ('file', '', '/tmp/junk.txt', '', '')), + ('file', None, '/tmp/junk.txt', None, None, None), + ('file', None, '/tmp/junk.txt', None, None)), ('http:/tmp/junk.txt', 'http:///tmp/junk.txt', - ('http', '', '/tmp/junk.txt', '', '', ''), - ('http', '', '/tmp/junk.txt', '', '')), + ('http', None, '/tmp/junk.txt', None, None, None), + ('http', None, '/tmp/junk.txt', None, None)), ('https:/tmp/junk.txt', 'https:///tmp/junk.txt', - ('https', '', '/tmp/junk.txt', '', '', ''), - ('https', '', '/tmp/junk.txt', '', '')), + ('https', None, '/tmp/junk.txt', None, None, None), + ('https', None, '/tmp/junk.txt', None, None)), ]) def test_roundtrips_normalization(self, bytes, url, url2, parsed, split): if bytes: @@ -310,17 +341,17 @@ def test_roundtrips_normalization(self, bytes, url, url2, parsed, split): @support.subTests('scheme', ('http', 'https')) @support.subTests('url,parsed,split', [ ('://www.python.org', - ('www.python.org', '', '', '', ''), - ('www.python.org', '', '', '')), + ('www.python.org', '', None, None, None), + ('www.python.org', '', None, None)), ('://www.python.org#abc', - ('www.python.org', '', '', '', 'abc'), - ('www.python.org', '', '', 'abc')), + ('www.python.org', '', None, None, 'abc'), + ('www.python.org', '', None, 'abc')), ('://www.python.org?q=abc', - ('www.python.org', '', '', 'q=abc', ''), - ('www.python.org', '', 'q=abc', '')), + ('www.python.org', '', None, 'q=abc', None), + ('www.python.org', '', 'q=abc', None)), ('://www.python.org/#abc', - ('www.python.org', '/', '', '', 'abc'), - ('www.python.org', '/', '', 'abc')), + ('www.python.org', '/', None, None, 'abc'), + ('www.python.org', '/', None, 'abc')), ('://a/b/c/d;p?q#f', ('a', '/b/c/d', 'p', 'q', 'f'), ('a', '/b/c/d;p', 'q', 'f')), @@ -342,16 +373,21 @@ def test_http_roundtrips(self, bytes, scheme, url, parsed, split): def checkJoin(self, base, relurl, expected, *, relroundtrip=True): with self.subTest(base=base, relurl=relurl): self.assertEqual(urllib.parse.urljoin(base, relurl), expected) - baseb = base.encode('ascii') - relurlb = relurl.encode('ascii') - expectedb = expected.encode('ascii') + baseb = str_encode(base) + relurlb = str_encode(relurl) + expectedb = str_encode(expected) self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) if relroundtrip: - relurl = urllib.parse.urlunsplit(urllib.parse.urlsplit(relurl)) - self.assertEqual(urllib.parse.urljoin(base, relurl), expected) - relurlb = urllib.parse.urlunsplit(urllib.parse.urlsplit(relurlb)) - self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) + relurl2 = urlunsplit(urlsplit(relurl)) + self.assertEqual(urllib.parse.urljoin(base, relurl2), expected) + relurlb2 = urlunsplit(urlsplit(relurlb)) + self.assertEqual(urllib.parse.urljoin(baseb, relurlb2), expectedb) + + relurl3 = urlunsplit(urlsplit(relurl, missing_as_none=True)) + self.assertEqual(urllib.parse.urljoin(base, relurl3), expected) + relurlb3 = urlunsplit(urlsplit(relurlb, missing_as_none=True)) + self.assertEqual(urllib.parse.urljoin(baseb, relurlb3), expectedb) @support.subTests('bytes', (False, True)) @support.subTests('u', ['Python', './Python','x-newscheme://foo.com/stuff','x://y','x:/y','x:/','/',]) @@ -387,7 +423,7 @@ def test_RFC1808(self): self.checkJoin(RFC1808_BASE, '../../g', 'http://a/g') # "abnormal" cases from RFC 1808: - self.checkJoin(RFC1808_BASE, '', 'http://a/b/c/d;p?q#f') + self.checkJoin(RFC1808_BASE, None, 'http://a/b/c/d;p?q#f') self.checkJoin(RFC1808_BASE, 'g.', 'http://a/b/c/g.') self.checkJoin(RFC1808_BASE, '.g', 'http://a/b/c/.g') self.checkJoin(RFC1808_BASE, 'g..', 'http://a/b/c/g..') @@ -411,8 +447,10 @@ def test_RFC1808(self): def test_RFC2368(self): # Issue 11467: path that starts with a number is not parsed correctly - self.assertEqual(urllib.parse.urlparse('mailto:1337@example.org'), + self.assertEqual(urlparse('mailto:1337@example.org'), ('mailto', '', '1337@example.org', '', '', '')) + self.assertEqual(urlparse('mailto:1337@example.org', missing_as_none=True), + ('mailto', None, '1337@example.org', None, None, None)) def test_RFC2396(self): # cases from RFC 2396 @@ -741,18 +779,18 @@ def test_RFC2732_invalid(self, bytes, invalid_url): @support.subTests('bytes', (False, True)) @support.subTests('url,defrag,frag', [ ('http://python.org#frag', 'http://python.org', 'frag'), - ('http://python.org', 'http://python.org', ''), + ('http://python.org', 'http://python.org', None), ('http://python.org/#frag', 'http://python.org/', 'frag'), - ('http://python.org/', 'http://python.org/', ''), + ('http://python.org/', 'http://python.org/', None), ('http://python.org/?q#frag', 'http://python.org/?q', 'frag'), - ('http://python.org/?q', 'http://python.org/?q', ''), + ('http://python.org/?q', 'http://python.org/?q', None), ('http://python.org/p#frag', 'http://python.org/p', 'frag'), - ('http://python.org/p?q', 'http://python.org/p?q', ''), + ('http://python.org/p?q', 'http://python.org/p?q', None), (RFC1808_BASE, 'http://a/b/c/d;p?q', 'f'), - (RFC2396_BASE, 'http://a/b/c/d;p?q', ''), + (RFC2396_BASE, 'http://a/b/c/d;p?q', None), ('http://a/b/c;p?q#f', 'http://a/b/c;p?q', 'f'), ('http://a/b/c;p?q#', 'http://a/b/c;p?q', ''), - ('http://a/b/c;p?q', 'http://a/b/c;p?q', ''), + ('http://a/b/c;p?q', 'http://a/b/c;p?q', None), ('http://a/b/c;p?#f', 'http://a/b/c;p?', 'f'), ('http://a/b/c;p#f', 'http://a/b/c;p', 'f'), ('http://a/b/c;?q#f', 'http://a/b/c;?q', 'f'), @@ -764,14 +802,19 @@ def test_RFC2732_invalid(self, bytes, invalid_url): ('//a/b/c;p?q#f', '//a/b/c;p?q', 'f'), ('://a/b/c;p?q#f', '://a/b/c;p?q', 'f'), ]) - def test_urldefrag(self, bytes, url, defrag, frag): + @support.subTests('missing_as_none', (False, True)) + def test_urldefrag(self, bytes, url, defrag, frag, missing_as_none): if bytes: url = str_encode(url) defrag = str_encode(defrag) frag = str_encode(frag) - result = urllib.parse.urldefrag(url) - hash = '#' if isinstance(url, str) else b'#' - self.assertEqual(result.geturl(), url.rstrip(hash)) + result = urllib.parse.urldefrag(url, missing_as_none=missing_as_none) + if not missing_as_none: + hash = '#' if isinstance(url, str) else b'#' + url = url.rstrip(hash) + if frag is None: + frag = url[:0] + self.assertEqual(result.geturl(), url) self.assertEqual(result, (defrag, frag)) self.assertEqual(result.url, defrag) self.assertEqual(result.fragment, frag) @@ -1001,26 +1044,27 @@ def test_attributes_bad_scheme(self, bytes, parse, scheme): if not url.isascii(): self.skipTest('non-ASCII bytes') url = url.encode("ascii") - p = parse(url) - self.assertEqual(p.scheme, b"" if bytes else "") + p = parse(url, missing_as_none=True) + self.assertIsNone(p.scheme) - def test_attributes_without_netloc(self): + @support.subTests('missing_as_none', (False, True)) + def test_attributes_without_netloc(self, missing_as_none): # This example is straight from RFC 3261. It looks like it # should allow the username, hostname, and port to be filled # in, but doesn't. Since it's a URI and doesn't use the # scheme://netloc syntax, the netloc and related attributes # should be left empty. uri = "sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15" - p = urllib.parse.urlsplit(uri) - self.assertEqual(p.netloc, "") + p = urllib.parse.urlsplit(uri, missing_as_none=missing_as_none) + self.assertEqual(p.netloc, None if missing_as_none else "") self.assertEqual(p.username, None) self.assertEqual(p.password, None) self.assertEqual(p.hostname, None) self.assertEqual(p.port, None) self.assertEqual(p.geturl(), uri) - p = urllib.parse.urlparse(uri) - self.assertEqual(p.netloc, "") + p = urllib.parse.urlparse(uri, missing_as_none=missing_as_none) + self.assertEqual(p.netloc, None if missing_as_none else "") self.assertEqual(p.username, None) self.assertEqual(p.password, None) self.assertEqual(p.hostname, None) @@ -1029,16 +1073,16 @@ def test_attributes_without_netloc(self): # You guessed it, repeating the test with bytes input uri = b"sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15" - p = urllib.parse.urlsplit(uri) - self.assertEqual(p.netloc, b"") + p = urllib.parse.urlsplit(uri, missing_as_none=missing_as_none) + self.assertEqual(p.netloc, None if missing_as_none else b"") self.assertEqual(p.username, None) self.assertEqual(p.password, None) self.assertEqual(p.hostname, None) self.assertEqual(p.port, None) self.assertEqual(p.geturl(), uri) - p = urllib.parse.urlparse(uri) - self.assertEqual(p.netloc, b"") + p = urllib.parse.urlparse(uri, missing_as_none=missing_as_none) + self.assertEqual(p.netloc, None if missing_as_none else b"") self.assertEqual(p.username, None) self.assertEqual(p.password, None) self.assertEqual(p.hostname, None) @@ -1052,67 +1096,86 @@ def test_noslash(self): self.assertEqual(urllib.parse.urlparse(b"http://example.com?blahblah=/foo"), (b'http', b'example.com', b'', b'', b'blahblah=/foo', b'')) - def test_withoutscheme(self): + @support.subTests('missing_as_none', (False, True)) + def test_withoutscheme(self, missing_as_none): # Test urlparse without scheme # Issue 754016: urlparse goes wrong with IP:port without scheme # RFC 1808 specifies that netloc should start with //, urlparse expects # the same, otherwise it classifies the portion of url as path. - self.assertEqual(urllib.parse.urlparse("path"), - ('','','path','','','')) - self.assertEqual(urllib.parse.urlparse("//www.python.org:80"), - ('','www.python.org:80','','','','')) - self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"), - ('http','www.python.org:80','','','','')) + none = None if missing_as_none else '' + self.assertEqual(urlparse("path", missing_as_none=missing_as_none), + (none, none, 'path', none, none, none)) + self.assertEqual(urlparse("//www.python.org:80", missing_as_none=missing_as_none), + (none, 'www.python.org:80', '', none, none, none)) + self.assertEqual(urlparse("http://www.python.org:80", missing_as_none=missing_as_none), + ('http', 'www.python.org:80', '', none, none, none)) # Repeat for bytes input - self.assertEqual(urllib.parse.urlparse(b"path"), - (b'',b'',b'path',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"//www.python.org:80"), - (b'',b'www.python.org:80',b'',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"), - (b'http',b'www.python.org:80',b'',b'',b'',b'')) + none = None if missing_as_none else b'' + self.assertEqual(urlparse(b"path", missing_as_none=missing_as_none), + (none, none, b'path', none, none, none)) + self.assertEqual(urlparse(b"//www.python.org:80", missing_as_none=missing_as_none), + (none, b'www.python.org:80', b'', none, none, none)) + self.assertEqual(urlparse(b"http://www.python.org:80", missing_as_none=missing_as_none), + (b'http', b'www.python.org:80', b'', none, none, none)) - def test_portseparator(self): + @support.subTests('missing_as_none', (False, True)) + def test_portseparator(self, missing_as_none): # Issue 754016 makes changes for port separator ':' from scheme separator - self.assertEqual(urllib.parse.urlparse("http:80"), ('http','','80','','','')) - self.assertEqual(urllib.parse.urlparse("https:80"), ('https','','80','','','')) - self.assertEqual(urllib.parse.urlparse("path:80"), ('path','','80','','','')) - self.assertEqual(urllib.parse.urlparse("http:"),('http','','','','','')) - self.assertEqual(urllib.parse.urlparse("https:"),('https','','','','','')) - self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"), - ('http','www.python.org:80','','','','')) + none = None if missing_as_none else '' + self.assertEqual(urlparse("http:80", missing_as_none=missing_as_none), + ('http', none, '80', none, none, none)) + self.assertEqual(urlparse("https:80", missing_as_none=missing_as_none), + ('https', none, '80', none, none, none)) + self.assertEqual(urlparse("path:80", missing_as_none=missing_as_none), + ('path', none, '80', none, none, none)) + self.assertEqual(urlparse("http:", missing_as_none=missing_as_none), + ('http', none, '', none, none, none)) + self.assertEqual(urlparse("https:", missing_as_none=missing_as_none), + ('https', none, '', none, none, none)) + self.assertEqual(urlparse("http://www.python.org:80", missing_as_none=missing_as_none), + ('http', 'www.python.org:80', '', none, none, none)) # As usual, need to check bytes input as well - self.assertEqual(urllib.parse.urlparse(b"http:80"), (b'http',b'',b'80',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"https:80"), (b'https',b'',b'80',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"path:80"), (b'path',b'',b'80',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"http:"),(b'http',b'',b'',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"https:"),(b'https',b'',b'',b'',b'',b'')) - self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"), - (b'http',b'www.python.org:80',b'',b'',b'',b'')) + none = None if missing_as_none else b'' + self.assertEqual(urlparse(b"http:80", missing_as_none=missing_as_none), + (b'http', none, b'80', none, none, none)) + self.assertEqual(urlparse(b"https:80", missing_as_none=missing_as_none), + (b'https', none, b'80', none, none, none)) + self.assertEqual(urlparse(b"path:80", missing_as_none=missing_as_none), + (b'path', none, b'80', none, none, none)) + self.assertEqual(urlparse(b"http:", missing_as_none=missing_as_none), + (b'http', none, b'', none, none, none)) + self.assertEqual(urlparse(b"https:", missing_as_none=missing_as_none), + (b'https', none, b'', none, none, none)) + self.assertEqual(urlparse(b"http://www.python.org:80", missing_as_none=missing_as_none), + (b'http', b'www.python.org:80', b'', none, none, none)) def test_usingsys(self): # Issue 3314: sys module is used in the error self.assertRaises(TypeError, urllib.parse.urlencode, "foo") - def test_anyscheme(self): + @support.subTests('missing_as_none', (False, True)) + def test_anyscheme(self, missing_as_none): # Issue 7904: s3://foo.com/stuff has netloc "foo.com". - self.assertEqual(urllib.parse.urlparse("s3://foo.com/stuff"), - ('s3', 'foo.com', '/stuff', '', '', '')) - self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"), - ('x-newscheme', 'foo.com', '/stuff', '', '', '')) - self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query#fragment"), - ('x-newscheme', 'foo.com', '/stuff', '', 'query', 'fragment')) - self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff?query"), - ('x-newscheme', 'foo.com', '/stuff', '', 'query', '')) + none = None if missing_as_none else '' + self.assertEqual(urlparse("s3://foo.com/stuff", missing_as_none=missing_as_none), + ('s3', 'foo.com', '/stuff', none, none, none)) + self.assertEqual(urlparse("x-newscheme://foo.com/stuff", missing_as_none=missing_as_none), + ('x-newscheme', 'foo.com', '/stuff', none, none, none)) + self.assertEqual(urlparse("x-newscheme://foo.com/stuff?query#fragment", missing_as_none=missing_as_none), + ('x-newscheme', 'foo.com', '/stuff', none, 'query', 'fragment')) + self.assertEqual(urlparse("x-newscheme://foo.com/stuff?query", missing_as_none=missing_as_none), + ('x-newscheme', 'foo.com', '/stuff', none, 'query', none)) # And for bytes... - self.assertEqual(urllib.parse.urlparse(b"s3://foo.com/stuff"), - (b's3', b'foo.com', b'/stuff', b'', b'', b'')) - self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff"), - (b'x-newscheme', b'foo.com', b'/stuff', b'', b'', b'')) - self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query#fragment"), - (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'fragment')) - self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query"), - (b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b'')) + none = None if missing_as_none else b'' + self.assertEqual(urlparse(b"s3://foo.com/stuff", missing_as_none=missing_as_none), + (b's3', b'foo.com', b'/stuff', none, none, none)) + self.assertEqual(urlparse(b"x-newscheme://foo.com/stuff", missing_as_none=missing_as_none), + (b'x-newscheme', b'foo.com', b'/stuff', none, none, none)) + self.assertEqual(urlparse(b"x-newscheme://foo.com/stuff?query#fragment", missing_as_none=missing_as_none), + (b'x-newscheme', b'foo.com', b'/stuff', none, b'query', b'fragment')) + self.assertEqual(urlparse(b"x-newscheme://foo.com/stuff?query", missing_as_none=missing_as_none), + (b'x-newscheme', b'foo.com', b'/stuff', none, b'query', none)) @support.subTests('func', (urllib.parse.urlparse, urllib.parse.urlsplit)) def test_default_scheme(self, func): @@ -1125,8 +1188,11 @@ def test_default_scheme(self, func): self.assertEqual(func("path", scheme="ftp").scheme, "ftp") self.assertEqual(func(b"path", scheme=b"ftp").scheme, b"ftp") self.assertEqual(func("path").scheme, "") + self.assertEqual(func("path", missing_as_none=True).scheme, None) self.assertEqual(func(b"path").scheme, b"") + self.assertEqual(func(b"path", missing_as_none=True).scheme, None) self.assertEqual(func(b"path", "").scheme, b"") + self.assertEqual(func(b"path", "", missing_as_none=True).scheme, b"") @support.subTests('url,attr,expected_frag', ( ("http:#frag", "path", "frag"), @@ -1151,9 +1217,16 @@ def test_parse_fragments(self, url, attr, expected_frag, func): "#" + expected_frag) self.assertEqual(func(url, "", False).fragment, "") + result = func(url, allow_fragments=False, missing_as_none=True) + self.assertIsNone(result.fragment) + self.assertTrue( + getattr(result, attr).endswith("#" + expected_frag)) + self.assertIsNone(func(url, "", False, missing_as_none=True).fragment) + result = func(url, allow_fragments=True) self.assertEqual(result.fragment, expected_frag) - self.assertNotEndsWith(getattr(result, attr), expected_frag) + self.assertFalse( + getattr(result, attr).endswith(expected_frag)) self.assertEqual(func(url, "", True).fragment, expected_frag) self.assertEqual(func(url).fragment, expected_frag) @@ -1182,19 +1255,10 @@ def test_mixed_types_rejected(self): with self.assertRaisesRegex(TypeError, "Cannot mix str"): urllib.parse.urljoin(b"http://python.org", "http://python.org") - @support.subTests('result_type', [ - urllib.parse.DefragResult, - urllib.parse.SplitResult, - urllib.parse.ParseResult, - ]) - def test_result_pairs(self, result_type): - # Check encoding and decoding between result pairs - str_type = result_type - num_args = len(str_type._fields) + def _check_result_type(self, str_type, str_args): bytes_type = str_type._encoded_counterpart self.assertIs(bytes_type._decoded_counterpart, str_type) - str_args = ('',) * num_args - bytes_args = (b'',) * num_args + bytes_args = tuple_encode(str_args) str_result = str_type(*str_args) bytes_result = bytes_type(*bytes_args) encoding = 'ascii' @@ -1213,6 +1277,169 @@ def test_result_pairs(self, result_type): self.assertEqual(str_result.encode(encoding), bytes_result) self.assertEqual(str_result.encode(encoding, errors), bytes_args) self.assertEqual(str_result.encode(encoding, errors), bytes_result) + for result in str_result, bytes_result: + self.assertEqual(copy.copy(result), result) + self.assertEqual(copy.deepcopy(result), result) + self.assertEqual(copy.replace(result), result) + self.assertEqual(result._replace(), result) + + def test_result_pairs__(self): + # Check encoding and decoding between result pairs + self._check_result_type(urllib.parse.DefragResult, ('', '')) + self._check_result_type(urllib.parse.DefragResult, ('', None)) + self._check_result_type(urllib.parse.SplitResult, ('', '', '', '', '')) + self._check_result_type(urllib.parse.SplitResult, (None, None, '', None, None)) + self._check_result_type(urllib.parse.ParseResult, ('', '', '', '', '', '')) + self._check_result_type(urllib.parse.ParseResult, (None, None, '', None, None, None)) + + def test_result_encoding_decoding(self): + def check(str_result, bytes_result): + self.assertEqual(str_result.encode(), bytes_result) + self.assertEqual(str_result.encode().geturl(), bytes_result.geturl()) + self.assertEqual(bytes_result.decode(), str_result) + self.assertEqual(bytes_result.decode().geturl(), str_result.geturl()) + + url = 'http://example.com/?#' + burl = url.encode() + for func in urldefrag, urlsplit, urlparse: + check(func(url, missing_as_none=True), func(burl, missing_as_none=True)) + check(func(url), func(burl)) + + def test_result_copying(self): + def check(result): + result2 = copy.copy(result) + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + result2 = copy.deepcopy(result) + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + result2 = copy.replace(result) + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + result2 = result._replace() + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + + url = 'http://example.com/?#' + burl = url.encode() + for func in urldefrag, urlsplit, urlparse: + check(func(url)) + check(func(url, missing_as_none=True)) + check(func(burl)) + check(func(burl, missing_as_none=True)) + + def test_result_pickling(self): + def check(result): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + pickled = pickle.dumps(result, proto) + result2 = pickle.loads(pickled) + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + + url = 'http://example.com/?#' + burl = url.encode() + for func in urldefrag, urlsplit, urlparse: + check(func(url)) + check(func(url, missing_as_none=True)) + check(func(burl)) + check(func(burl, missing_as_none=True)) + + def test_result_compat_unpickling(self): + def check(result, pickles): + for pickled in pickles: + result2 = pickle.loads(pickled) + self.assertEqual(result2, result) + self.assertEqual(result2.geturl(), result.geturl()) + + url = 'http://example.com/?#' + burl = url.encode() + # Pre-3.15 data. + check(urldefrag(url), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResult\nc__builtin__\ntuple\n(Vhttp://example.com/?\nV\nttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResult\nc__builtin__\ntuple\n(X\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00ttR.', + b'\x80\x02curlparse\nDefragResult\nX\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00\x86\x81.', + b'\x80\x03curllib.parse\nDefragResult\nX\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00\x86\x81.', + b'\x80\x04\x958\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0cDefragResult\x93\x8c\x14http://example.com/?\x8c\x00\x86\x81.', + )) + check(urldefrag(burl), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\n(Vhttp://example.com/?\nVlatin1\ntRc__builtin__\nbytes\n(tRttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\n(X\x14\x00\x00\x00http://example.com/?X\x06\x00\x00\x00latin1tRc__builtin__\nbytes\n)RttR.', + b'\x80\x02curlparse\nDefragResultBytes\nc_codecs\nencode\nX\x14\x00\x00\x00http://example.com/?X\x06\x00\x00\x00latin1\x86Rc__builtin__\nbytes\n)R\x86\x81.', + b'\x80\x03curllib.parse\nDefragResultBytes\nC\x14http://example.com/?C\x00\x86\x81.', + b'\x80\x04\x95=\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x11DefragResultBytes\x93C\x14http://example.com/?C\x00\x86\x81.', + )) + check(urlsplit(url), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResult\nc__builtin__\ntuple\n(Vhttp\nVexample.com\nV/\nV\np0\ng0\nttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResult\nc__builtin__\ntuple\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00ttR.', + b'\x80\x02curlparse\nSplitResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00t\x81.', + b'\x80\x03curllib.parse\nSplitResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00t\x81.', + b'\x80\x04\x95;\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0bSplitResult\x93(\x8c\x04http\x8c\x0bexample.com\x8c\x01/\x8c\x00\x94h\x00t\x81.', + )) + check(urlsplit(burl), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\np0\n(Vhttp\nVlatin1\np1\ntRg0\n(Vexample.com\ng1\ntRg0\n(V/\ng1\ntRc__builtin__\nbytes\n(tRp2\ng2\nttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\nq\x00(X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01tRh\x00(X\x0b\x00\x00\x00example.comh\x01tRh\x00(X\x01\x00\x00\x00/h\x01tRc__builtin__\nbytes\n)Rq\x02h\x02ttR.', + b'\x80\x02curlparse\nSplitResultBytes\n(c_codecs\nencode\nq\x00X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01\x86Rh\x00X\x0b\x00\x00\x00example.comh\x01\x86Rh\x00X\x01\x00\x00\x00/h\x01\x86Rc__builtin__\nbytes\n)Rq\x02h\x02t\x81.', + b'\x80\x03curllib.parse\nSplitResultBytes\n(C\x04httpC\x0bexample.comC\x01/C\x00q\x00h\x00t\x81.', + b'\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x10SplitResultBytes\x93(C\x04httpC\x0bexample.comC\x01/C\x00\x94h\x00t\x81.', + )) + check(urlparse(url), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResult\nc__builtin__\ntuple\n(Vhttp\nVexample.com\nV/\nV\np0\ng0\ng0\nttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResult\nc__builtin__\ntuple\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00h\x00ttR.', + b'\x80\x02curlparse\nParseResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00h\x00t\x81.', + b'\x80\x03curllib.parse\nParseResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00h\x00t\x81.', + b'\x80\x04\x95=\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0bParseResult\x93(\x8c\x04http\x8c\x0bexample.com\x8c\x01/\x8c\x00\x94h\x00h\x00t\x81.', + )) + check(urlparse(burl), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\np0\n(Vhttp\nVlatin1\np1\ntRg0\n(Vexample.com\ng1\ntRg0\n(V/\ng1\ntRc__builtin__\nbytes\n(tRp2\ng2\ng2\nttR.', + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\nq\x00(X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01tRh\x00(X\x0b\x00\x00\x00example.comh\x01tRh\x00(X\x01\x00\x00\x00/h\x01tRc__builtin__\nbytes\n)Rq\x02h\x02h\x02ttR.', + b'\x80\x02curlparse\nParseResultBytes\n(c_codecs\nencode\nq\x00X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01\x86Rh\x00X\x0b\x00\x00\x00example.comh\x01\x86Rh\x00X\x01\x00\x00\x00/h\x01\x86Rc__builtin__\nbytes\n)Rq\x02h\x02h\x02t\x81.', + b'\x80\x03curllib.parse\nParseResultBytes\n(C\x04httpC\x0bexample.comC\x01/C\x00q\x00h\x00h\x00t\x81.', + b'\x80\x04\x95B\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x10ParseResultBytes\x93(C\x04httpC\x0bexample.comC\x01/C\x00\x94h\x00h\x00t\x81.', + )) + + # 3.15 data with missing_as_none=True. + check(urldefrag(url, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResult\nc__builtin__\ntuple\n(Vhttp://example.com/?\nV\nttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResult\nc__builtin__\ntuple\n(X\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00ttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nDefragResult\nX\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00\x86\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nDefragResult\nX\x14\x00\x00\x00http://example.com/?X\x00\x00\x00\x00\x86\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95K\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0cDefragResult\x93\x8c\x14http://example.com/?\x8c\x00\x86\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) + check(urldefrag(burl, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\n(Vhttp://example.com/?\nVlatin1\ntRc__builtin__\nbytes\n(tRttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nDefragResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\n(X\x14\x00\x00\x00http://example.com/?X\x06\x00\x00\x00latin1tRc__builtin__\nbytes\n)RttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nDefragResultBytes\nc_codecs\nencode\nX\x14\x00\x00\x00http://example.com/?X\x06\x00\x00\x00latin1\x86Rc__builtin__\nbytes\n)R\x86\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nDefragResultBytes\nC\x14http://example.com/?C\x00\x86\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95P\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x11DefragResultBytes\x93C\x14http://example.com/?C\x00\x86\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) + check(urlsplit(url, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResult\nc__builtin__\ntuple\n(Vhttp\nVexample.com\nV/\nV\np0\ng0\nttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResult\nc__builtin__\ntuple\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00ttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nSplitResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nSplitResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/X\x00\x00\x00\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95N\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0bSplitResult\x93(\x8c\x04http\x8c\x0bexample.com\x8c\x01/\x8c\x00\x94h\x00t\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) + check(urlsplit(burl, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\np0\n(Vhttp\nVlatin1\np1\ntRg0\n(Vexample.com\ng1\ntRg0\n(V/\ng1\ntRc__builtin__\nbytes\n(tRp2\ng2\nttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nSplitResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\nq\x00(X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01tRh\x00(X\x0b\x00\x00\x00example.comh\x01tRh\x00(X\x01\x00\x00\x00/h\x01tRc__builtin__\nbytes\n)Rq\x02h\x02ttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nSplitResultBytes\n(c_codecs\nencode\nq\x00X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01\x86Rh\x00X\x0b\x00\x00\x00example.comh\x01\x86Rh\x00X\x01\x00\x00\x00/h\x01\x86Rc__builtin__\nbytes\n)Rq\x02h\x02t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nSplitResultBytes\n(C\x04httpC\x0bexample.comC\x01/C\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95S\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x10SplitResultBytes\x93(C\x04httpC\x0bexample.comC\x01/C\x00\x94h\x00t\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) + check(urlparse(url, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResult\nc__builtin__\ntuple\n(Vhttp\nVexample.com\nV/\nNV\np0\ng0\nttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResult\nc__builtin__\ntuple\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/NX\x00\x00\x00\x00q\x00h\x00ttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nParseResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/NX\x00\x00\x00\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nParseResult\n(X\x04\x00\x00\x00httpX\x0b\x00\x00\x00example.comX\x01\x00\x00\x00/NX\x00\x00\x00\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95O\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x0bParseResult\x93(\x8c\x04http\x8c\x0bexample.com\x8c\x01/N\x8c\x00\x94h\x00t\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) + check(urlparse(burl, missing_as_none=True), ( + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\np0\n(Vhttp\nVlatin1\np1\ntRg0\n(Vexample.com\ng1\ntRg0\n(V/\ng1\ntRNc__builtin__\nbytes\n(tRp2\ng2\nttR(N(dV_keep_empty\nI01\nstb.', + b'ccopy_reg\n_reconstructor\n(curlparse\nParseResultBytes\nc__builtin__\ntuple\n(c_codecs\nencode\nq\x00(X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01tRh\x00(X\x0b\x00\x00\x00example.comh\x01tRh\x00(X\x01\x00\x00\x00/h\x01tRNc__builtin__\nbytes\n)Rq\x02h\x02ttR(N}X\x0b\x00\x00\x00_keep_emptyI01\nstb.', + b'\x80\x02curlparse\nParseResultBytes\n(c_codecs\nencode\nq\x00X\x04\x00\x00\x00httpX\x06\x00\x00\x00latin1q\x01\x86Rh\x00X\x0b\x00\x00\x00example.comh\x01\x86Rh\x00X\x01\x00\x00\x00/h\x01\x86RNc__builtin__\nbytes\n)Rq\x02h\x02t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x03curllib.parse\nParseResultBytes\n(C\x04httpC\x0bexample.comC\x01/NC\x00q\x00h\x00t\x81N}X\x0b\x00\x00\x00_keep_empty\x88s\x86b.', + b'\x80\x04\x95T\x00\x00\x00\x00\x00\x00\x00\x8c\x0curllib.parse\x8c\x10ParseResultBytes\x93(C\x04httpC\x0bexample.comC\x01/NC\x00\x94h\x00t\x81N}\x8c\x0b_keep_empty\x88s\x86b.', + )) def test_parse_qs_encoding(self): result = urllib.parse.parse_qs("key=\u0141%E9", encoding="latin-1") @@ -1457,6 +1684,11 @@ def test_telurl_params(self): self.assertEqual(p1.path, '+1-201-555-0123') self.assertEqual(p1.params, '') + p1 = urllib.parse.urlparse('tel:+1-201-555-0123', missing_as_none=True) + self.assertEqual(p1.scheme, 'tel') + self.assertEqual(p1.path, '+1-201-555-0123') + self.assertEqual(p1.params, None) + p1 = urllib.parse.urlparse('tel:7042;phone-context=example.com') self.assertEqual(p1.scheme, 'tel') self.assertEqual(p1.path, '7042') @@ -1757,6 +1989,8 @@ def test_to_bytes_deprecation(self): def str_encode(s): + if s is None: + return None return s.encode('ascii') def tuple_encode(t): diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py index 79fd6abaa1c..e917f8b61bb 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -112,7 +112,10 @@ def _encode_result(obj, encoding=_implicit_encoding, def _decode_args(args, encoding=_implicit_encoding, errors=_implicit_errors): - return tuple(x.decode(encoding, errors) if x else '' for x in args) + return tuple(x.decode(encoding, errors) if x + else '' if x is not None + else None + for x in args) def _coerce_args(*args): # Invokes decode if necessary to create str args @@ -120,13 +123,20 @@ def _coerce_args(*args): # an appropriate result coercion function # - noop for str inputs # - encoding function otherwise - str_input = isinstance(args[0], str) - for arg in args[1:]: - # We special-case the empty string to support the - # "scheme=''" default argument to some functions - if arg and isinstance(arg, str) != str_input: - raise TypeError("Cannot mix str and non-str arguments") - if str_input: + str_input = None + for arg in args: + if arg: + if str_input is None: + str_input = isinstance(arg, str) + else: + if isinstance(arg, str) != str_input: + raise TypeError("Cannot mix str and non-str arguments") + if str_input is None: + for arg in args: + if arg is not None: + str_input = isinstance(arg, str) + break + if str_input is not False: return args + (_noop,) return _decode_args(args) + (_encode_result,) @@ -136,7 +146,14 @@ class _ResultMixinStr(object): __slots__ = () def encode(self, encoding='ascii', errors='strict'): - return self._encoded_counterpart(*(x.encode(encoding, errors) for x in self)) + result = self._encoded_counterpart(*(x.encode(encoding, errors) + if x is not None else None + for x in self)) + try: + result._keep_empty = self._keep_empty + except AttributeError: + pass + return result class _ResultMixinBytes(object): @@ -144,7 +161,14 @@ class _ResultMixinBytes(object): __slots__ = () def decode(self, encoding='ascii', errors='strict'): - return self._decoded_counterpart(*(x.decode(encoding, errors) for x in self)) + result = self._decoded_counterpart(*(x.decode(encoding, errors) + if x is not None else None + for x in self)) + try: + result._keep_empty = self._keep_empty + except AttributeError: + pass + return result class _NetlocResultMixinBase(object): @@ -191,6 +215,8 @@ class _NetlocResultMixinStr(_NetlocResultMixinBase, _ResultMixinStr): @property def _userinfo(self): netloc = self.netloc + if netloc is None: + return None, None userinfo, have_info, hostinfo = netloc.rpartition('@') if have_info: username, have_password, password = userinfo.partition(':') @@ -203,6 +229,8 @@ def _userinfo(self): @property def _hostinfo(self): netloc = self.netloc + if netloc is None: + return None, None _, _, hostinfo = netloc.rpartition('@') _, have_open_br, bracketed = hostinfo.partition('[') if have_open_br: @@ -221,6 +249,8 @@ class _NetlocResultMixinBytes(_NetlocResultMixinBase, _ResultMixinBytes): @property def _userinfo(self): netloc = self.netloc + if netloc is None: + return None, None userinfo, have_info, hostinfo = netloc.rpartition(b'@') if have_info: username, have_password, password = userinfo.partition(b':') @@ -233,6 +263,8 @@ def _userinfo(self): @property def _hostinfo(self): netloc = self.netloc + if netloc is None: + return None, None _, _, hostinfo = netloc.rpartition(b'@') _, have_open_br, bracketed = hostinfo.partition(b'[') if have_open_br: @@ -245,11 +277,70 @@ def _hostinfo(self): return hostname, port -_DefragResultBase = namedtuple('_DefragResultBase', 'url fragment') -_SplitResultBase = namedtuple( - '_SplitResultBase', 'scheme netloc path query fragment') -_ParseResultBase = namedtuple( - '_ParseResultBase', 'scheme netloc path params query fragment') +_UNSPECIFIED = ['not specified'] +_MISSING_AS_NONE_DEFAULT = False + +class _ResultBase: + __slots__ = () + + def __replace__(self, /, **kwargs): + result = super().__replace__(**kwargs) + try: + result._keep_empty = self._keep_empty + except AttributeError: + pass + return result + + def _replace(self, /, **kwargs): + result = super()._replace(**kwargs) + try: + result._keep_empty = self._keep_empty + except AttributeError: + pass + return result + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + def __getstate__(self): + state = super().__getstate__() + try: + if state[1]['_keep_empty'] == _MISSING_AS_NONE_DEFAULT: + del state[1]['_keep_empty'] + if state == (None, {}): + state = None + except LookupError: + pass + return state + + +class _DefragResultBase(_ResultBase, namedtuple('_DefragResultBase', 'url fragment')): + __slots__ = ('_keep_empty',) + + def geturl(self): + if self.fragment or (self.fragment is not None and + getattr(self, '_keep_empty', _MISSING_AS_NONE_DEFAULT)): + return self.url + self._HASH + self.fragment + else: + return self.url + +class _SplitResultBase(_ResultBase, namedtuple( + '_SplitResultBase', 'scheme netloc path query fragment')): + __slots__ = ('_keep_empty',) + + def geturl(self): + return urlunsplit(self) + +class _ParseResultBase(_ResultBase, namedtuple( + '_ParseResultBase', 'scheme netloc path params query fragment')): + __slots__ = ('_keep_empty',) + + def geturl(self): + return urlunparse(self) + _DefragResultBase.__doc__ = """ DefragResult(url, fragment) @@ -320,40 +411,24 @@ def _hostinfo(self): # Structured result objects for string data class DefragResult(_DefragResultBase, _ResultMixinStr): __slots__ = () - def geturl(self): - if self.fragment: - return self.url + '#' + self.fragment - else: - return self.url + _HASH = '#' class SplitResult(_SplitResultBase, _NetlocResultMixinStr): __slots__ = () - def geturl(self): - return urlunsplit(self) class ParseResult(_ParseResultBase, _NetlocResultMixinStr): __slots__ = () - def geturl(self): - return urlunparse(self) # Structured result objects for bytes data class DefragResultBytes(_DefragResultBase, _ResultMixinBytes): __slots__ = () - def geturl(self): - if self.fragment: - return self.url + b'#' + self.fragment - else: - return self.url + _HASH = b'#' class SplitResultBytes(_SplitResultBase, _NetlocResultMixinBytes): __slots__ = () - def geturl(self): - return urlunsplit(self) class ParseResultBytes(_ParseResultBase, _NetlocResultMixinBytes): __slots__ = () - def geturl(self): - return urlunparse(self) # Set up the encode/decode result pairs def _fix_result_transcoding(): @@ -369,7 +444,7 @@ def _fix_result_transcoding(): _fix_result_transcoding() del _fix_result_transcoding -def urlparse(url, scheme='', allow_fragments=True): +def urlparse(url, scheme=None, allow_fragments=True, *, missing_as_none=_MISSING_AS_NONE_DEFAULT): """Parse a URL into 6 components: :///;?# @@ -390,23 +465,33 @@ def urlparse(url, scheme='', allow_fragments=True): Note that % escapes are not expanded. """ url, scheme, _coerce_result = _coerce_args(url, scheme) + if url is None: + url = '' scheme, netloc, url, params, query, fragment = _urlparse(url, scheme, allow_fragments) - result = ParseResult(scheme or '', netloc or '', url, params or '', query or '', fragment or '') - return _coerce_result(result) + if not missing_as_none: + if scheme is None: scheme = '' + if netloc is None: netloc = '' + if params is None: params = '' + if query is None: query = '' + if fragment is None: fragment = '' + result = ParseResult(scheme, netloc, url, params, query, fragment) + result = _coerce_result(result) + result._keep_empty = missing_as_none + return result def _urlparse(url, scheme=None, allow_fragments=True): scheme, netloc, url, query, fragment = _urlsplit(url, scheme, allow_fragments) if (scheme or '') in uses_params and ';' in url: - url, params = _splitparams(url, allow_none=True) + url, params = _splitparams(url, missing_as_none=True) else: params = None return (scheme, netloc, url, params, query, fragment) -def _splitparams(url, allow_none=False): +def _splitparams(url, missing_as_none=False): if '/' in url: i = url.find(';', url.rfind('/')) if i < 0: - return url, None if allow_none else '' + return url, None if missing_as_none else '' else: i = url.find(';') return url[:i], url[i+1:] @@ -468,7 +553,7 @@ def _check_bracketed_host(hostname): # typed=True avoids BytesWarnings being emitted during cache key # comparison since this API supports both bytes and str input. @functools.lru_cache(typed=True) -def urlsplit(url, scheme='', allow_fragments=True): +def urlsplit(url, scheme=None, allow_fragments=True, *, missing_as_none=_MISSING_AS_NONE_DEFAULT): """Parse a URL into 5 components: :///?# @@ -490,9 +575,18 @@ def urlsplit(url, scheme='', allow_fragments=True): """ url, scheme, _coerce_result = _coerce_args(url, scheme) + if url is None: + url = '' scheme, netloc, url, query, fragment = _urlsplit(url, scheme, allow_fragments) - v = SplitResult(scheme or '', netloc or '', url, query or '', fragment or '') - return _coerce_result(v) + if not missing_as_none: + if scheme is None: scheme = '' + if netloc is None: netloc = '' + if query is None: query = '' + if fragment is None: fragment = '' + result = SplitResult(scheme, netloc, url, query, fragment) + result = _coerce_result(result) + result._keep_empty = missing_as_none + return result def _urlsplit(url, scheme=None, allow_fragments=True): # Only lstrip url as some applications rely on preserving trailing space. @@ -528,38 +622,61 @@ def _urlsplit(url, scheme=None, allow_fragments=True): _checknetloc(netloc) return (scheme, netloc, url, query, fragment) -def urlunparse(components): +def urlunparse(components, *, keep_empty=_UNSPECIFIED): """Put a parsed URL back together again. This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had redundant delimiters, e.g. a ? with an empty query - (the draft states that these are equivalent).""" + (the draft states that these are equivalent) and keep_empty is false + or components is the result of the urlparse() call with + missing_as_none=False.""" scheme, netloc, url, params, query, fragment, _coerce_result = ( _coerce_args(*components)) - if not netloc: - if scheme and scheme in uses_netloc and (not url or url[:1] == '/'): - netloc = '' - else: - netloc = None - if params: + if keep_empty is _UNSPECIFIED: + keep_empty = getattr(components, '_keep_empty', _MISSING_AS_NONE_DEFAULT) + elif keep_empty and not getattr(components, '_keep_empty', True): + raise ValueError('Cannot distinguish between empty and not defined ' + 'URI components in the result of parsing URL with ' + 'missing_as_none=False') + if not keep_empty: + if not netloc: + if scheme and scheme in uses_netloc and (not url or url[:1] == '/'): + netloc = '' + else: + netloc = None + if not scheme: scheme = None + if not params: params = None + if not query: query = None + if not fragment: fragment = None + if params is not None: url = "%s;%s" % (url, params) - return _coerce_result(_urlunsplit(scheme or None, netloc, url, - query or None, fragment or None)) + return _coerce_result(_urlunsplit(scheme, netloc, url, query, fragment)) -def urlunsplit(components): +def urlunsplit(components, *, keep_empty=_UNSPECIFIED): """Combine the elements of a tuple as returned by urlsplit() into a complete URL as a string. The data argument can be any five-item iterable. This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had unnecessary delimiters (for example, a ? with an - empty query; the RFC states that these are equivalent).""" + empty query; the RFC states that these are equivalent) and keep_empty + is false or components is the result of the urlsplit() call with + missing_as_none=False.""" scheme, netloc, url, query, fragment, _coerce_result = ( _coerce_args(*components)) - if not netloc: - if scheme and scheme in uses_netloc and (not url or url[:1] == '/'): - netloc = '' - else: - netloc = None - return _coerce_result(_urlunsplit(scheme or None, netloc, url, - query or None, fragment or None)) + if keep_empty is _UNSPECIFIED: + keep_empty = getattr(components, '_keep_empty', _MISSING_AS_NONE_DEFAULT) + elif keep_empty and not getattr(components, '_keep_empty', True): + raise ValueError('Cannot distinguish between empty and not defined ' + 'URI components in the result of parsing URL with ' + 'missing_as_none=False') + if not keep_empty: + if not netloc: + if scheme and scheme in uses_netloc and (not url or url[:1] == '/'): + netloc = '' + else: + netloc = None + if not scheme: scheme = None + if not query: query = None + if not fragment: fragment = None + return _coerce_result(_urlunsplit(scheme, netloc, url, query, fragment)) def _urlunsplit(scheme, netloc, url, query, fragment): if netloc is not None: @@ -647,21 +764,24 @@ def urljoin(base, url, allow_fragments=True): resolved_path) or '/', query, fragment)) -def urldefrag(url): +def urldefrag(url, *, missing_as_none=_MISSING_AS_NONE_DEFAULT): """Removes any existing fragment from URL. Returns a tuple of the defragmented URL and the fragment. If the URL contained no fragments, the second element is the - empty string. + empty string or None if missing_as_none is True. """ url, _coerce_result = _coerce_args(url) if '#' in url: s, n, p, q, frag = _urlsplit(url) defrag = _urlunsplit(s, n, p, q, None) else: - frag = '' + frag = None defrag = url - return _coerce_result(DefragResult(defrag, frag or '')) + if not missing_as_none and frag is None: frag = '' + result = _coerce_result(DefragResult(defrag, frag)) + result._keep_empty = missing_as_none + return result _hexdig = '0123456789ABCDEFabcdef' _hextobyte = None diff --git a/Mac/Resources/app-store-compliance.patch b/Mac/Resources/app-store-compliance.patch index f4b7decc01c..e5d1e7da866 100644 --- a/Mac/Resources/app-store-compliance.patch +++ b/Mac/Resources/app-store-compliance.patch @@ -1,21 +1,21 @@ diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py -index d6c83a75c1c..19ed4e01091 100644 +index 49a292df934..e1669a0c9b2 100644 --- a/Lib/test/test_urlparse.py +++ b/Lib/test/test_urlparse.py -@@ -237,11 +237,6 @@ def test_roundtrips(self): - '','',''), +@@ -282,11 +282,6 @@ def test_qs(self, orig, expect): + None,None,None), ('git+ssh', 'git@github.com','/user/project.git', - '', '')), + None, None)), - ('itms-services://?action=download-manifest&url=https://example.com/app', -- ('itms-services', '', '', '', -- 'action=download-manifest&url=https://example.com/app', ''), +- ('itms-services', '', '', None, +- 'action=download-manifest&url=https://example.com/app', None), - ('itms-services', '', '', -- 'action=download-manifest&url=https://example.com/app', '')), +- 'action=download-manifest&url=https://example.com/app', None)), ('+scheme:path/to/file', - ('', '', '+scheme:path/to/file', '', '', ''), - ('', '', '+scheme:path/to/file', '', '')), + (None, None, '+scheme:path/to/file', None, None, None), + (None, None, '+scheme:path/to/file', None, None)), diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py -index 8f724f907d4..148caf742c9 100644 +index e917f8b61bb..8575172573f 100644 --- a/Lib/urllib/parse.py +++ b/Lib/urllib/parse.py @@ -59,7 +59,7 @@ diff --git a/Misc/NEWS.d/next/Library/2024-11-27-13-11-16.gh-issue-67041.ym2WKK.rst b/Misc/NEWS.d/next/Library/2024-11-27-13-11-16.gh-issue-67041.ym2WKK.rst new file mode 100644 index 00000000000..9ad1e28eac1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-11-27-13-11-16.gh-issue-67041.ym2WKK.rst @@ -0,0 +1,6 @@ +Add the *missing_as_none* parameter to :func:`~urllib.parse.urlparse`, +:func:`~urllib.parse.urlsplit` and :func:`~urllib.parse.urldefrag` +functions. Add the *keep_empty* parameter to +:func:`~urllib.parse.urlunparse` and :func:`~urllib.parse.urlunsplit` +functions. This allows to distinguish between empty and not defined URI +components and preserve empty components. From 77bf4ba732a8736910bd6b7ec5a58b8ee833c95f Mon Sep 17 00:00:00 2001 From: stratakis Date: Thu, 22 Jan 2026 18:06:36 +0100 Subject: [PATCH 049/133] gh-142779: Initialize reserved field for proper padding (#142780) The jitdump specification specifies a reserved field for padding. Initialize it so no garbage data is embedded in the jitdump files. --- Python/perf_jit_trampoline.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c index 0ffa906d85c..f51ab1b47a0 100644 --- a/Python/perf_jit_trampoline.c +++ b/Python/perf_jit_trampoline.c @@ -398,6 +398,7 @@ static void perf_map_jit_write_header(int pid, FILE* out_file) { header.version = 1; // Current jitdump version header.size = sizeof(Header); // Header size for validation header.elf_mach_target = GetElfMachineArchitecture(); // Target architecture + header.reserved = 0; // padding reserved for future use header.process_id = pid; // Process identifier header.time_stamp = get_current_time_microseconds(); // Creation time header.flags = 0; // No special flags currently used From a966d94e76d91ef60f9912a98a3869f38ecd438b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:21:07 -0800 Subject: [PATCH 050/133] gh-144157: Optimize bytes.translate() by deferring change detection (GH-144158) Optimize bytes.translate() by deferring change detection Move the equality check out of the hot loop to allow better compiler optimization. Instead of checking each byte during translation, perform a single memcmp at the end to determine if the input can be returned unchanged. This allows compilers to unroll and pipeline the loops, resulting in ~2x throughput improvement for medium-to-large inputs (tested on an AMD zen2). No change observed on small inputs. It will also be faster for bytes subclasses as those do not need change detection. --- .../2026-01-22-16-20-16.gh-issue-144157.dxyp7k.rst | 2 ++ Objects/bytesobject.c | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-16-20-16.gh-issue-144157.dxyp7k.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-16-20-16.gh-issue-144157.dxyp7k.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-16-20-16.gh-issue-144157.dxyp7k.rst new file mode 100644 index 00000000000..ff62d739d78 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-16-20-16.gh-issue-144157.dxyp7k.rst @@ -0,0 +1,2 @@ +:meth:`bytes.translate` now allows the compiler to unroll its loop more +usefully for a 2x speedup in the common no-deletions specified case. diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 2b0925017f2..56de99bde11 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2237,11 +2237,15 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table, /* If no deletions are required, use faster code */ for (i = inlen; --i >= 0; ) { c = Py_CHARMASK(*input++); - if (Py_CHARMASK((*output++ = table_chars[c])) != c) - changed = 1; + *output++ = table_chars[c]; } - if (!changed && PyBytes_CheckExact(input_obj)) { - Py_SETREF(result, Py_NewRef(input_obj)); + /* Check if anything changed (for returning original object) */ + /* We save this check until the end so that the compiler will */ + /* unroll the loop above leading to MUCH faster code. */ + if (PyBytes_CheckExact(input_obj)) { + if (memcmp(PyBytes_AS_STRING(input_obj), output_start, inlen) == 0) { + Py_SETREF(result, Py_NewRef(input_obj)); + } } PyBuffer_Release(&del_table_view); PyBuffer_Release(&table_view); From bcf9cb0217fdbab5dc6b812648e61bfa196e7110 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 22 Jan 2026 14:02:30 -0500 Subject: [PATCH 051/133] gh-143756: Fix potential data race in SSLContext.load_cert_chain (gh-143818) Concurrent calls to `load_cert_chain` caused data races in OpenSSL code. --- ...-01-13-16-19-50.gh-issue-143756.LQOra1.rst | 1 + Modules/_ssl.c | 154 ++++++++++-------- Modules/clinic/_ssl.c.h | 4 +- 3 files changed, 87 insertions(+), 72 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-13-16-19-50.gh-issue-143756.LQOra1.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-13-16-19-50.gh-issue-143756.LQOra1.rst b/Misc/NEWS.d/next/Library/2026-01-13-16-19-50.gh-issue-143756.LQOra1.rst new file mode 100644 index 00000000000..fc7eefff861 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-13-16-19-50.gh-issue-143756.LQOra1.rst @@ -0,0 +1 @@ +Fix potential thread safety issues in :mod:`ssl` module. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 2bcf864e759..e240b889d86 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -43,14 +43,17 @@ /* Redefined below for Windows debug builds after important #includes */ #define _PySSL_FIX_ERRNO -#define PySSL_BEGIN_ALLOW_THREADS_S(save, mutex) \ - do { (save) = PyEval_SaveThread(); PyMutex_Lock(mutex); } while(0) -#define PySSL_END_ALLOW_THREADS_S(save, mutex) \ - do { PyMutex_Unlock(mutex); PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0) +#define PySSL_BEGIN_ALLOW_THREADS_S(save) \ + do { (save) = PyEval_SaveThread(); } while(0) +#define PySSL_END_ALLOW_THREADS_S(save) \ + do { PyEval_RestoreThread(save); _PySSL_FIX_ERRNO; } while(0) #define PySSL_BEGIN_ALLOW_THREADS(self) { \ PyThreadState *_save = NULL; \ - PySSL_BEGIN_ALLOW_THREADS_S(_save, &self->tstate_mutex); -#define PySSL_END_ALLOW_THREADS(self) PySSL_END_ALLOW_THREADS_S(_save, &self->tstate_mutex); } + PySSL_BEGIN_ALLOW_THREADS_S(_save); \ + PyMutex_Lock(&(self)->tstate_mutex); +#define PySSL_END_ALLOW_THREADS(self) \ + PyMutex_Unlock(&(self)->tstate_mutex); \ + PySSL_END_ALLOW_THREADS_S(_save); } #if defined(HAVE_POLL_H) #include @@ -4543,8 +4546,73 @@ _password_callback(char *buf, int size, int rwflag, void *userdata) return -1; } +static PyObject * +load_cert_chain_lock_held(PySSLContext *self, _PySSLPasswordInfo *pw_info, + PyObject *certfile_bytes, PyObject *keyfile_bytes) +{ + int r; + PyObject *ret = NULL; + + pem_password_cb *orig_passwd_cb = SSL_CTX_get_default_passwd_cb(self->ctx); + void *orig_passwd_userdata = SSL_CTX_get_default_passwd_cb_userdata(self->ctx); + + SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback); + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, pw_info); + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); + r = SSL_CTX_use_certificate_chain_file(self->ctx, + PyBytes_AS_STRING(certfile_bytes)); + PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); + if (r != 1) { + if (pw_info->error) { + ERR_clear_error(); + /* the password callback has already set the error information */ + } + else if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + ERR_clear_error(); + } + else { + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); + } + goto error; + } + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); + r = SSL_CTX_use_PrivateKey_file(self->ctx, + PyBytes_AS_STRING(keyfile_bytes ? keyfile_bytes : certfile_bytes), + SSL_FILETYPE_PEM); + PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); + if (r != 1) { + if (pw_info->error) { + ERR_clear_error(); + /* the password callback has already set the error information */ + } + else if (errno != 0) { + PyErr_SetFromErrno(PyExc_OSError); + ERR_clear_error(); + } + else { + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); + } + goto error; + } + + PySSL_BEGIN_ALLOW_THREADS_S(pw_info->thread_state); + r = SSL_CTX_check_private_key(self->ctx); + PySSL_END_ALLOW_THREADS_S(pw_info->thread_state); + if (r != 1) { + _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); + goto error; + } + ret = Py_None; +error: + SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); + return ret; +} + /*[clinic input] -@critical_section _ssl._SSLContext.load_cert_chain certfile: object keyfile: object = None @@ -4555,13 +4623,11 @@ _ssl._SSLContext.load_cert_chain static PyObject * _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, PyObject *keyfile, PyObject *password) -/*[clinic end generated code: output=9480bc1c380e2095 input=6c7c5e8b73e4264b]*/ +/*[clinic end generated code: output=9480bc1c380e2095 input=30bc7e967ea01a58]*/ { PyObject *certfile_bytes = NULL, *keyfile_bytes = NULL; - pem_password_cb *orig_passwd_cb = SSL_CTX_get_default_passwd_cb(self->ctx); - void *orig_passwd_userdata = SSL_CTX_get_default_passwd_cb_userdata(self->ctx); _PySSLPasswordInfo pw_info = { NULL, NULL, NULL, 0, 0 }; - int r; + PyObject *ret = NULL; errno = 0; ERR_clear_error(); @@ -4579,76 +4645,26 @@ _ssl__SSLContext_load_cert_chain_impl(PySSLContext *self, PyObject *certfile, PyErr_SetString(PyExc_TypeError, "keyfile should be a valid filesystem path"); } - goto error; + goto done; } if (password != Py_None) { if (PyCallable_Check(password)) { pw_info.callable = password; } else if (!_pwinfo_set(&pw_info, password, "password should be a string or callable")) { - goto error; + goto done; } - SSL_CTX_set_default_passwd_cb(self->ctx, _password_callback); - SSL_CTX_set_default_passwd_cb_userdata(self->ctx, &pw_info); } - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - r = SSL_CTX_use_certificate_chain_file(self->ctx, - PyBytes_AS_STRING(certfile_bytes)); - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - if (r != 1) { - if (pw_info.error) { - ERR_clear_error(); - /* the password callback has already set the error information */ - } - else if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); - ERR_clear_error(); - } - else { - _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); - } - goto error; - } - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - r = SSL_CTX_use_PrivateKey_file(self->ctx, - PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), - SSL_FILETYPE_PEM); - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - Py_CLEAR(keyfile_bytes); - Py_CLEAR(certfile_bytes); - if (r != 1) { - if (pw_info.error) { - ERR_clear_error(); - /* the password callback has already set the error information */ - } - else if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); - ERR_clear_error(); - } - else { - _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); - } - goto error; - } - PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - r = SSL_CTX_check_private_key(self->ctx); - PySSL_END_ALLOW_THREADS_S(pw_info.thread_state, &self->tstate_mutex); - if (r != 1) { - _setSSLError(get_state_ctx(self), NULL, 0, __FILE__, __LINE__); - goto error; - } - SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); - PyMem_Free(pw_info.password); - Py_RETURN_NONE; -error: - SSL_CTX_set_default_passwd_cb(self->ctx, orig_passwd_cb); - SSL_CTX_set_default_passwd_cb_userdata(self->ctx, orig_passwd_userdata); + PyMutex_Lock(&self->tstate_mutex); + ret = load_cert_chain_lock_held(self, &pw_info, certfile_bytes, keyfile_bytes); + PyMutex_Unlock(&self->tstate_mutex); + +done: PyMem_Free(pw_info.password); Py_XDECREF(keyfile_bytes); Py_XDECREF(certfile_bytes); - return NULL; + return ret; } /* internal helper function, returns -1 on error diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h index d1fb024903e..8c35c8443b7 100644 --- a/Modules/clinic/_ssl.c.h +++ b/Modules/clinic/_ssl.c.h @@ -1829,9 +1829,7 @@ _ssl__SSLContext_load_cert_chain(PyObject *self, PyObject *const *args, Py_ssize } password = args[2]; skip_optional_pos: - Py_BEGIN_CRITICAL_SECTION(self); return_value = _ssl__SSLContext_load_cert_chain_impl((PySSLContext *)self, certfile, keyfile, password); - Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -3325,4 +3323,4 @@ exit: #ifndef _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ -/*[clinic end generated code: output=3b6c9cbfc4660ecb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e29d5ada294f97bb input=a9049054013a1b77]*/ From ee4e14aa4c1150438b18d828770a967ca2019d43 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Thu, 22 Jan 2026 14:02:48 -0500 Subject: [PATCH 052/133] gh-143756: Avoid borrowed reference in SSL code (gh-143816) GET_SOCKET() returned a borrowed reference, which was potentially unsafe. Also, refactor out some common code. --- Modules/_ssl.c | 144 ++++++++++++++++--------------------------------- 1 file changed, 46 insertions(+), 98 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index e240b889d86..22865bdfc3f 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -423,26 +423,6 @@ typedef enum { #define ERRSTR1(x,y,z) (x ":" y ": " z) #define ERRSTR(x) ERRSTR1("_ssl.c", Py_STRINGIFY(__LINE__), x) -// Get the socket from a PySSLSocket, if it has one. -// Return a borrowed reference. -static inline PySocketSockObject* GET_SOCKET(PySSLSocket *obj) { - if (obj->Socket) { - PyObject *sock; - if (PyWeakref_GetRef(obj->Socket, &sock)) { - // GET_SOCKET() returns a borrowed reference - Py_DECREF(sock); - } - else { - // dead weak reference - sock = Py_None; - } - return (PySocketSockObject *)sock; // borrowed reference - } - else { - return NULL; - } -} - /* If sock is NULL, use a timeout of 0 second */ #define GET_SOCKET_TIMEOUT(sock) \ ((sock != NULL) ? (sock)->sock_timeout : 0) @@ -794,6 +774,35 @@ _ssl_deprecated(const char* msg, int stacklevel) { #define PY_SSL_DEPRECATED(name, stacklevel, ret) \ if (_ssl_deprecated((name), (stacklevel)) == -1) return (ret) +// Get the socket from a PySSLSocket, if it has one. +// Stores a strong reference in out_sock. +static int +get_socket(PySSLSocket *obj, PySocketSockObject **out_sock, + const char *filename, int lineno) +{ + if (!obj->Socket) { + *out_sock = NULL; + return 0; + } + PySocketSockObject *sock; + int res = PyWeakref_GetRef(obj->Socket, (PyObject **)&sock); + if (res == 0 || sock->sock_fd == INVALID_SOCKET) { + _setSSLError(get_state_sock(obj), + "Underlying socket connection gone", + PY_SSL_ERROR_NO_SOCKET, filename, lineno); + *out_sock = NULL; + return -1; + } + if (sock != NULL) { + /* just in case the blocking state of the socket has been changed */ + int nonblocking = (sock->sock_timeout >= 0); + BIO_set_nbio(SSL_get_rbio(obj->ssl), nonblocking); + BIO_set_nbio(SSL_get_wbio(obj->ssl), nonblocking); + } + *out_sock = sock; + return res; +} + /* * SSL objects */ @@ -1021,24 +1030,13 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) int ret; _PySSLError err; PyObject *exc = NULL; - int sockstate, nonblocking; - PySocketSockObject *sock = GET_SOCKET(self); + int sockstate; PyTime_t timeout, deadline = 0; int has_timeout; - if (sock) { - if (((PyObject*)sock) == Py_None) { - _setSSLError(get_state_sock(self), - "Underlying socket connection gone", - PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); - return NULL; - } - Py_INCREF(sock); - - /* just in case the blocking state of the socket has been changed */ - nonblocking = (sock->sock_timeout >= 0); - BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); - BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + PySocketSockObject *sock = NULL; + if (get_socket(self, &sock, __FILE__, __LINE__) < 0) { + return NULL; } timeout = GET_SOCKET_TIMEOUT(sock); @@ -2610,22 +2608,12 @@ _ssl__SSLSocket_sendfile_impl(PySSLSocket *self, int fd, Py_off_t offset, int sockstate; _PySSLError err; PyObject *exc = NULL; - PySocketSockObject *sock = GET_SOCKET(self); PyTime_t timeout, deadline = 0; int has_timeout; - if (sock != NULL) { - if ((PyObject *)sock == Py_None) { - _setSSLError(get_state_sock(self), - "Underlying socket connection gone", - PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); - return NULL; - } - Py_INCREF(sock); - /* just in case the blocking state of the socket has been changed */ - int nonblocking = (sock->sock_timeout >= 0); - BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); - BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + PySocketSockObject *sock = NULL; + if (get_socket(self, &sock, __FILE__, __LINE__) < 0) { + return NULL; } timeout = GET_SOCKET_TIMEOUT(sock); @@ -2747,26 +2735,12 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) int sockstate; _PySSLError err; PyObject *exc = NULL; - int nonblocking; - PySocketSockObject *sock = GET_SOCKET(self); PyTime_t timeout, deadline = 0; int has_timeout; - if (sock != NULL) { - if (((PyObject*)sock) == Py_None) { - _setSSLError(get_state_sock(self), - "Underlying socket connection gone", - PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); - return NULL; - } - Py_INCREF(sock); - } - - if (sock != NULL) { - /* just in case the blocking state of the socket has been changed */ - nonblocking = (sock->sock_timeout >= 0); - BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); - BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + PySocketSockObject *sock = NULL; + if (get_socket(self, &sock, __FILE__, __LINE__) < 0) { + return NULL; } timeout = GET_SOCKET_TIMEOUT(sock); @@ -2896,8 +2870,6 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, int sockstate; _PySSLError err; PyObject *exc = NULL; - int nonblocking; - PySocketSockObject *sock = GET_SOCKET(self); PyTime_t timeout, deadline = 0; int has_timeout; @@ -2906,14 +2878,9 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, return NULL; } - if (sock != NULL) { - if (((PyObject*)sock) == Py_None) { - _setSSLError(get_state_sock(self), - "Underlying socket connection gone", - PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); - return NULL; - } - Py_INCREF(sock); + PySocketSockObject *sock = NULL; + if (get_socket(self, &sock, __FILE__, __LINE__) < 0) { + return NULL; } if (!group_right_1) { @@ -2944,13 +2911,6 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, } } - if (sock != NULL) { - /* just in case the blocking state of the socket has been changed */ - nonblocking = (sock->sock_timeout >= 0); - BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); - BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); - } - timeout = GET_SOCKET_TIMEOUT(sock); has_timeout = (timeout > 0); if (has_timeout) @@ -3041,26 +3001,14 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self) { _PySSLError err; PyObject *exc = NULL; - int sockstate, nonblocking, ret; + int sockstate, ret; int zeros = 0; - PySocketSockObject *sock = GET_SOCKET(self); PyTime_t timeout, deadline = 0; int has_timeout; - if (sock != NULL) { - /* Guard against closed socket */ - if ((((PyObject*)sock) == Py_None) || (sock->sock_fd == INVALID_SOCKET)) { - _setSSLError(get_state_sock(self), - "Underlying socket connection gone", - PY_SSL_ERROR_NO_SOCKET, __FILE__, __LINE__); - return NULL; - } - Py_INCREF(sock); - - /* Just in case the blocking state of the socket has been changed */ - nonblocking = (sock->sock_timeout >= 0); - BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking); - BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking); + PySocketSockObject *sock = NULL; + if (get_socket(self, &sock, __FILE__, __LINE__) < 0) { + return NULL; } timeout = GET_SOCKET_TIMEOUT(sock); From 5b2d49b7da25bdd7bde603c71ac8685993008b96 Mon Sep 17 00:00:00 2001 From: Dimma Don't Date: Thu, 22 Jan 2026 16:30:13 -0500 Subject: [PATCH 053/133] Add source links to documentation for Windows-specific modules (GH-130244) --- Doc/library/msvcrt.rst | 2 ++ Doc/library/winreg.rst | 6 ++++-- Doc/library/winsound.rst | 8 ++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Doc/library/msvcrt.rst b/Doc/library/msvcrt.rst index a2c5e375d2c..80f3ae4ee3f 100644 --- a/Doc/library/msvcrt.rst +++ b/Doc/library/msvcrt.rst @@ -7,6 +7,8 @@ .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`PC/msvcrtmodule.c` + -------------- These functions provide access to some useful capabilities on Windows platforms. diff --git a/Doc/library/winreg.rst b/Doc/library/winreg.rst index 89def6e2afe..d167c41ab72 100644 --- a/Doc/library/winreg.rst +++ b/Doc/library/winreg.rst @@ -7,6 +7,8 @@ .. sectionauthor:: Mark Hammond +**Source code:** :source:`PC/winreg.c` + -------------- These functions expose the Windows registry API to Python. Instead of using an @@ -25,7 +27,7 @@ to explicitly close them. .. _functions: Functions ------------------- +--------- This module offers the following functions: @@ -554,7 +556,7 @@ This module offers the following functions: .. _constants: Constants ------------------- +--------- The following constants are defined for use in many :mod:`winreg` functions. diff --git a/Doc/library/winsound.rst b/Doc/library/winsound.rst index 93c0c025982..755b94fc0fb 100644 --- a/Doc/library/winsound.rst +++ b/Doc/library/winsound.rst @@ -8,6 +8,8 @@ .. moduleauthor:: Toby Dickenson .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`PC/winsound.c` + -------------- The :mod:`winsound` module provides access to the basic sound-playing machinery @@ -16,6 +18,9 @@ provided by Windows platforms. It includes functions and several constants. .. availability:: Windows. +Functions +--------- + .. function:: Beep(frequency, duration) Beep the PC's speaker. The *frequency* parameter specifies frequency, in hertz, @@ -46,6 +51,9 @@ provided by Windows platforms. It includes functions and several constants. error, :exc:`RuntimeError` is raised. +Constants +--------- + .. data:: SND_FILENAME The *sound* parameter is the name of a WAV file. Do not use with From f8262b84f5b76e45cfea9d73b09657919926850f Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Thu, 22 Jan 2026 22:00:37 +0000 Subject: [PATCH 054/133] gh-143513: Remove importlib.abc documentation for removed ABCs (#143605) In 3.11 ResourceReader, Traversable, & TraversableResources moved from importlib.abc to importlib.resources.abc (commit e712a5b277866a71c195f38c1b5d87d9126dba3e). In 3.12 old import locations were deprecated (commit 71848c960927af801656026203371c41ad139b5a). In 3.14 backwards-compat support was removed (commit 0751511d24295c39fdf2f5b2255e3fa3d796ce4d). Co-authored-by: Brett Cannon --- Doc/library/importlib.rst | 166 -------------------------------------- Doc/whatsnew/3.7.rst | 6 +- Misc/NEWS.d/3.7.0a4.rst | 2 +- Misc/NEWS.d/3.7.0b1.rst | 2 +- Misc/NEWS.d/3.7.0b4.rst | 2 +- Misc/NEWS.d/3.8.0a1.rst | 2 +- 6 files changed, 7 insertions(+), 173 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index c5ea78c1683..26964348f5c 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -596,172 +596,6 @@ ABC hierarchy:: itself does not end in ``__init__``. -.. class:: ResourceReader - - *Superseded by TraversableResources* - - An :term:`abstract base class` to provide the ability to read - *resources*. - - From the perspective of this ABC, a *resource* is a binary - artifact that is shipped within a package. Typically this is - something like a data file that lives next to the ``__init__.py`` - file of the package. The purpose of this class is to help abstract - out the accessing of such data files so that it does not matter if - the package and its data file(s) are stored e.g. in a zip file - versus on the file system. - - For any of methods of this class, a *resource* argument is - expected to be a :term:`path-like object` which represents - conceptually just a file name. This means that no subdirectory - paths should be included in the *resource* argument. This is - because the location of the package the reader is for, acts as the - "directory". Hence the metaphor for directories and file - names is packages and resources, respectively. This is also why - instances of this class are expected to directly correlate to - a specific package (instead of potentially representing multiple - packages or a module). - - Loaders that wish to support resource reading are expected to - provide a method called ``get_resource_reader(fullname)`` which - returns an object implementing this ABC's interface. If the module - specified by fullname is not a package, this method should return - :const:`None`. An object compatible with this ABC should only be - returned when the specified module is a package. - - .. versionadded:: 3.7 - - .. deprecated-removed:: 3.12 3.14 - Use :class:`importlib.resources.abc.TraversableResources` instead. - - .. method:: open_resource(resource) - :abstractmethod: - - Returns an opened, :term:`file-like object` for binary reading - of the *resource*. - - If the resource cannot be found, :exc:`FileNotFoundError` is - raised. - - .. method:: resource_path(resource) - :abstractmethod: - - Returns the file system path to the *resource*. - - If the resource does not concretely exist on the file system, - raise :exc:`FileNotFoundError`. - - .. method:: is_resource(name) - :abstractmethod: - - Returns ``True`` if the named *name* is considered a resource. - :exc:`FileNotFoundError` is raised if *name* does not exist. - - .. method:: contents() - :abstractmethod: - - Returns an :term:`iterable` of strings over the contents of - the package. Do note that it is not required that all names - returned by the iterator be actual resources, e.g. it is - acceptable to return names for which :meth:`is_resource` would - be false. - - Allowing non-resource names to be returned is to allow for - situations where how a package and its resources are stored - are known a priori and the non-resource names would be useful. - For instance, returning subdirectory names is allowed so that - when it is known that the package and resources are stored on - the file system then those subdirectory names can be used - directly. - - The abstract method returns an iterable of no items. - - -.. class:: Traversable - - An object with a subset of :class:`pathlib.Path` methods suitable for - traversing directories and opening files. - - For a representation of the object on the file-system, use - :meth:`importlib.resources.as_file`. - - .. versionadded:: 3.9 - - .. deprecated-removed:: 3.12 3.14 - Use :class:`importlib.resources.abc.Traversable` instead. - - .. attribute:: name - - Abstract. The base name of this object without any parent references. - - .. method:: iterdir() - :abstractmethod: - - Yield ``Traversable`` objects in ``self``. - - .. method:: is_dir() - :abstractmethod: - - Return ``True`` if ``self`` is a directory. - - .. method:: is_file() - :abstractmethod: - - Return ``True`` if ``self`` is a file. - - .. method:: joinpath(child) - :abstractmethod: - - Return Traversable child in ``self``. - - .. method:: __truediv__(child) - :abstractmethod: - - Return ``Traversable`` child in ``self``. - - .. method:: open(mode='r', *args, **kwargs) - :abstractmethod: - - *mode* may be 'r' or 'rb' to open as text or binary. Return a handle - suitable for reading (same as :attr:`pathlib.Path.open`). - - When opening as text, accepts encoding parameters such as those - accepted by :class:`io.TextIOWrapper`. - - .. method:: read_bytes() - - Read contents of ``self`` as bytes. - - .. method:: read_text(encoding=None) - - Read contents of ``self`` as text. - - -.. class:: TraversableResources - - An abstract base class for resource readers capable of serving - the :meth:`importlib.resources.files` interface. Subclasses - :class:`importlib.resources.abc.ResourceReader` and provides - concrete implementations of the :class:`importlib.resources.abc.ResourceReader`'s - abstract methods. Therefore, any loader supplying - :class:`importlib.abc.TraversableResources` also supplies ResourceReader. - - Loaders that wish to support resource reading are expected to - implement this interface. - - .. versionadded:: 3.9 - - .. deprecated-removed:: 3.12 3.14 - Use :class:`importlib.resources.abc.TraversableResources` instead. - - .. method:: files() - :abstractmethod: - - Returns a :class:`importlib.resources.abc.Traversable` object for the loaded - package. - - - :mod:`importlib.machinery` -- Importers and path hooks ------------------------------------------------------ diff --git a/Doc/whatsnew/3.7.rst b/Doc/whatsnew/3.7.rst index 32ca965b7d0..5dd47cdac96 100644 --- a/Doc/whatsnew/3.7.rst +++ b/Doc/whatsnew/3.7.rst @@ -604,7 +604,7 @@ new ABC for access to, opening, and reading *resources* inside packages. Resources are roughly similar to files inside packages, but they needn't be actual files on the physical file system. Module loaders can provide a :meth:`!get_resource_reader` function which returns -a :class:`importlib.abc.ResourceReader` instance to support this +a :class:`!importlib.abc.ResourceReader` instance to support this new API. Built-in file path loaders and zip file loaders both support this. Contributed by Barry Warsaw and Brett Cannon in :issue:`32248`. @@ -1043,7 +1043,7 @@ window are shown and hidden in the Options menu. importlib --------- -The :class:`importlib.abc.ResourceReader` ABC was introduced to +The :class:`!importlib.abc.ResourceReader` ABC was introduced to support the loading of resources from packages. See also :ref:`whatsnew37_importlib_resources`. (Contributed by Barry Warsaw, Brett Cannon in :issue:`32248`.) @@ -2032,7 +2032,7 @@ both deprecated in Python 3.4 now emit :exc:`DeprecationWarning`. (Contributed by Matthias Bussonnier in :issue:`29576`.) The :class:`importlib.abc.ResourceLoader` ABC has been deprecated in -favour of :class:`importlib.abc.ResourceReader`. +favour of :class:`!importlib.abc.ResourceReader`. locale diff --git a/Misc/NEWS.d/3.7.0a4.rst b/Misc/NEWS.d/3.7.0a4.rst index 2ceb9e78e04..691ac0f4a8c 100644 --- a/Misc/NEWS.d/3.7.0a4.rst +++ b/Misc/NEWS.d/3.7.0a4.rst @@ -403,7 +403,7 @@ SOCK_CLOEXEC. .. nonce: zmO8G2 .. section: Library -Add :class:`importlib.abc.ResourceReader` as an ABC for loaders to provide a +Add :class:`!importlib.abc.ResourceReader` as an ABC for loaders to provide a unified API for reading resources contained within packages. Also add :mod:`importlib.resources` as the port of ``importlib_resources``. diff --git a/Misc/NEWS.d/3.7.0b1.rst b/Misc/NEWS.d/3.7.0b1.rst index c9786e55c20..d785f6d8c4c 100644 --- a/Misc/NEWS.d/3.7.0b1.rst +++ b/Misc/NEWS.d/3.7.0b1.rst @@ -598,7 +598,7 @@ Add socket.getblocking() method. .. nonce: zmO8G2 .. section: Library -Add :mod:`importlib.resources` and :class:`importlib.abc.ResourceReader` as +Add :mod:`importlib.resources` and :class:`!importlib.abc.ResourceReader` as the unified API for reading resources contained within packages. Loaders wishing to support resource reading must implement the :meth:`get_resource_reader` method. File-based and zipimport-based diff --git a/Misc/NEWS.d/3.7.0b4.rst b/Misc/NEWS.d/3.7.0b4.rst index 93627f54900..789d96dffd6 100644 --- a/Misc/NEWS.d/3.7.0b4.rst +++ b/Misc/NEWS.d/3.7.0b4.rst @@ -152,7 +152,7 @@ Ensure line-endings are respected when using lib2to3. .. section: Library Have :func:`importlib.resources.contents` and -:meth:`importlib.abc.ResourceReader.contents` return an :term:`iterable` +:meth:`!importlib.abc.ResourceReader.contents` return an :term:`iterable` instead of an :term:`iterator`. .. diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst index 93995bc8fea..3a6966deb87 100644 --- a/Misc/NEWS.d/3.8.0a1.rst +++ b/Misc/NEWS.d/3.8.0a1.rst @@ -5130,7 +5130,7 @@ Ensure line-endings are respected when using lib2to3. .. section: Library Have :func:`importlib.resources.contents` and -:meth:`importlib.abc.ResourceReader.contents` return an :term:`iterable` +:meth:`!importlib.abc.ResourceReader.contents` return an :term:`iterable` instead of an :term:`iterator`. .. From f3dd0cae6cea38b15b42b20d39c7142a4a0f716e Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Fri, 23 Jan 2026 16:06:47 +0800 Subject: [PATCH 055/133] Doc: fix incorrect reference in `isasyncgenfunction` docs (GH-144099) Fix incorrect reference in isasyncgenfunction docs --- Doc/library/inspect.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 9e53dd70ab5..5133f9f0c8e 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -524,7 +524,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes): .. versionchanged:: 3.13 Functions wrapped in :func:`functools.partialmethod` now return ``True`` - if the wrapped function is a :term:`coroutine function`. + if the wrapped function is a :term:`asynchronous generator` function. .. function:: isasyncgen(object) From 052e55e7d44718fe46cbba0ca995cb8fcc359413 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Fri, 23 Jan 2026 08:59:35 -0600 Subject: [PATCH 056/133] gh-144125: email: verify headers are sound in BytesGenerator Co-authored-by: Denis Ledoux Co-authored-by: Denis Ledoux <5822488+beledouxdenis@users.noreply.github.com> Co-authored-by: Petr Viktorin <302922+encukou@users.noreply.github.com> Co-authored-by: Bas Bloemsaat <1586868+basbloemsaat@users.noreply.github.com> --- Lib/email/generator.py | 12 +++++++++++- Lib/test/test_email/test_generator.py | 4 +++- Lib/test/test_email/test_policy.py | 6 +++++- .../2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst | 4 ++++ 4 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst diff --git a/Lib/email/generator.py b/Lib/email/generator.py index 03524c96559..cebbc416087 100644 --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -22,6 +22,7 @@ NLCRE = re.compile(r'\r\n|\r|\n') fcre = re.compile(r'^From ', re.MULTILINE) NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') +NEWLINE_WITHOUT_FWSP_BYTES = re.compile(br'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') class Generator: @@ -429,7 +430,16 @@ def _write_headers(self, msg): # This is almost the same as the string version, except for handling # strings with 8bit bytes. for h, v in msg.raw_items(): - self._fp.write(self.policy.fold_binary(h, v)) + folded = self.policy.fold_binary(h, v) + if self.policy.verify_generated_headers: + linesep = self.policy.linesep.encode() + if not folded.endswith(linesep): + raise HeaderWriteError( + f'folded header does not end with {linesep!r}: {folded!r}') + if NEWLINE_WITHOUT_FWSP_BYTES.search(folded.removesuffix(linesep)): + raise HeaderWriteError( + f'folded header contains newline: {folded!r}') + self._fp.write(folded) # A blank line always separates headers from body self.write(self._NL) diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py index c75a842c335..3ca79edf6a6 100644 --- a/Lib/test/test_email/test_generator.py +++ b/Lib/test/test_email/test_generator.py @@ -313,7 +313,7 @@ def test_flatten_unicode_linesep(self): self.assertEqual(s.getvalue(), self.typ(expected)) def test_verify_generated_headers(self): - """gh-121650: by default the generator prevents header injection""" + # gh-121650: by default the generator prevents header injection class LiteralHeader(str): name = 'Header' def fold(self, **kwargs): @@ -334,6 +334,8 @@ def fold(self, **kwargs): with self.assertRaises(email.errors.HeaderWriteError): message.as_string() + with self.assertRaises(email.errors.HeaderWriteError): + message.as_bytes() class TestBytesGenerator(TestGeneratorBase, TestEmailBase): diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py index baa35fd68e4..71ec0febb0f 100644 --- a/Lib/test/test_email/test_policy.py +++ b/Lib/test/test_email/test_policy.py @@ -296,7 +296,7 @@ def test_short_maxlen_error(self): policy.fold("Subject", subject) def test_verify_generated_headers(self): - """Turning protection off allows header injection""" + # Turning protection off allows header injection policy = email.policy.default.clone(verify_generated_headers=False) for text in ( 'Header: Value\r\nBad: Injection\r\n', @@ -319,6 +319,10 @@ def fold(self, **kwargs): message.as_string(), f"{text}\nBody", ) + self.assertEqual( + message.as_bytes(), + f"{text}\nBody".encode(), + ) # XXX: Need subclassing tests. # For adding subclassed objects, make sure the usual rules apply (subclass diff --git a/Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst b/Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst new file mode 100644 index 00000000000..e6333e72497 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst @@ -0,0 +1,4 @@ +:mod:`~email.generator.BytesGenerator` will now refuse to serialize (write) headers +that are unsafely folded or delimited; see +:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas +Bloemsaat and Petr Viktorin in :gh:`121650`). From 03e651d601c7d54ffe93ef1bbd4f66fafb89eded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Fri, 23 Jan 2026 17:34:21 +0100 Subject: [PATCH 057/133] Programming FAQ: fix some punctuaction typos (GH-144058) Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/faq/programming.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst index 6f9dfa8616e..138a5ca7a75 100644 --- a/Doc/faq/programming.rst +++ b/Doc/faq/programming.rst @@ -1226,13 +1226,13 @@ This converts the list into a set, thereby removing duplicates, and then back into a list. -How do you remove multiple items from a list --------------------------------------------- +How do you remove multiple items from a list? +--------------------------------------------- As with removing duplicates, explicitly iterating in reverse with a delete condition is one possibility. However, it is easier and faster to use slice replacement with an implicit or explicit forward iteration. -Here are three variations.:: +Here are three variations:: mylist[:] = filter(keep_function, mylist) mylist[:] = (x for x in mylist if keep_condition) From 70e67f579e20036d82c59cd604b5dc73dd3c6a8a Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 23 Jan 2026 17:51:29 +0100 Subject: [PATCH 058/133] gh-141376: smelly.py: Print only smelly symbols, or all of them with --verbose (GH-141394) Instead of long and uninteresting output for all checked libraries, only print found issues by default. Add a new -v/--verbose option to list all symbols (useful for checking that the script finds the symbols). --- Tools/build/smelly.py | 222 +++++++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 99 deletions(-) diff --git a/Tools/build/smelly.py b/Tools/build/smelly.py index 424fa6ad4a1..7197d70bc8b 100755 --- a/Tools/build/smelly.py +++ b/Tools/build/smelly.py @@ -1,7 +1,14 @@ #!/usr/bin/env python -# Script checking that all symbols exported by libpython start with Py or _Py +"""Check exported symbols -import os.path +Check that all symbols exported by CPython (libpython, stdlib extension +modules, and similar) start with Py or _Py, or are covered by an exception. +""" + +import argparse +import dataclasses +import functools +import pathlib import subprocess import sys import sysconfig @@ -23,150 +30,167 @@ IGNORED_EXTENSION = "_ctypes_test" -def is_local_symbol_type(symtype): - # Ignore local symbols. +@dataclasses.dataclass +class Library: + path: pathlib.Path + is_dynamic: bool - # If lowercase, the symbol is usually local; if uppercase, the symbol - # is global (external). There are however a few lowercase symbols that - # are shown for special global symbols ("u", "v" and "w"). - if symtype.islower() and symtype not in "uvw": + @functools.cached_property + def is_ignored(self): + name_without_extemnsions = self.path.name.partition('.')[0] + return name_without_extemnsions == IGNORED_EXTENSION + + +@dataclasses.dataclass +class Symbol: + name: str + type: str + library: str + + def __str__(self): + return f"{self.name!r} (type {self.type}) from {self.library.path}" + + @functools.cached_property + def is_local(self): + # If lowercase, the symbol is usually local; if uppercase, the symbol + # is global (external). There are however a few lowercase symbols that + # are shown for special global symbols ("u", "v" and "w"). + if self.type.islower() and self.type not in "uvw": + return True + + return False + + @functools.cached_property + def is_smelly(self): + if self.is_local: + return False + if self.name.startswith(ALLOWED_PREFIXES): + return False + if self.name in EXCEPTIONS: + return False + if not self.library.is_dynamic and self.name.startswith( + ALLOWED_STATIC_PREFIXES): + return False + if self.library.is_ignored: + return False return True - return False + @functools.cached_property + def _sort_key(self): + return self.name, self.library.path + + def __lt__(self, other_symbol): + return self._sort_key < other_symbol._sort_key -def get_exported_symbols(library, dynamic=False): - print(f"Check that {library} only exports symbols starting with Py or _Py") - +def get_exported_symbols(library): + # Only look at dynamic symbols args = ['nm', '--no-sort'] - if dynamic: + if library.is_dynamic: args.append('--dynamic') - args.append(library) - print(f"+ {' '.join(args)}") + args.append(library.path) proc = subprocess.run(args, stdout=subprocess.PIPE, encoding='utf-8') if proc.returncode: + print("+", args) sys.stdout.write(proc.stdout) sys.exit(proc.returncode) stdout = proc.stdout.rstrip() if not stdout: raise Exception("command output is empty") - return stdout - - -def get_smelly_symbols(stdout, dynamic=False): - smelly_symbols = [] - python_symbols = [] - local_symbols = [] + symbols = [] for line in stdout.splitlines(): - # Split line '0000000000001b80 D PyTextIOWrapper_Type' if not line: continue + # Split lines like '0000000000001b80 D PyTextIOWrapper_Type' parts = line.split(maxsplit=2) + # Ignore lines like ' U PyDict_SetItemString' + # and headers like 'pystrtod.o:' if len(parts) < 3: continue - symtype = parts[1].strip() - symbol = parts[-1] - result = f'{symbol} (type: {symtype})' + symbol = Symbol(name=parts[-1], type=parts[1], library=library) + if not symbol.is_local: + symbols.append(symbol) - if (symbol.startswith(ALLOWED_PREFIXES) or - symbol in EXCEPTIONS or - (not dynamic and symbol.startswith(ALLOWED_STATIC_PREFIXES))): - python_symbols.append(result) - continue - - if is_local_symbol_type(symtype): - local_symbols.append(result) - else: - smelly_symbols.append(result) - - if local_symbols: - print(f"Ignore {len(local_symbols)} local symbols") - return smelly_symbols, python_symbols + return symbols -def check_library(library, dynamic=False): - nm_output = get_exported_symbols(library, dynamic) - smelly_symbols, python_symbols = get_smelly_symbols(nm_output, dynamic) - - if not smelly_symbols: - print(f"OK: no smelly symbol found ({len(python_symbols)} Python symbols)") - return 0 - - print() - smelly_symbols.sort() - for symbol in smelly_symbols: - print(f"Smelly symbol: {symbol}") - - print() - print(f"ERROR: Found {len(smelly_symbols)} smelly symbols!") - return len(smelly_symbols) - - -def check_extensions(): - print(__file__) +def get_extension_libraries(): # This assumes pybuilddir.txt is in same directory as pyconfig.h. # In the case of out-of-tree builds, we can't assume pybuilddir.txt is # in the source folder. - config_dir = os.path.dirname(sysconfig.get_config_h_filename()) - filename = os.path.join(config_dir, "pybuilddir.txt") + config_dir = pathlib.Path(sysconfig.get_config_h_filename()).parent try: - with open(filename, encoding="utf-8") as fp: - pybuilddir = fp.readline() - except FileNotFoundError: - print(f"Cannot check extensions because {filename} does not exist") - return True + config_dir = config_dir.relative_to(pathlib.Path.cwd(), walk_up=True) + except ValueError: + pass + filename = config_dir / "pybuilddir.txt" + pybuilddir = filename.read_text().strip() - print(f"Check extension modules from {pybuilddir} directory") - builddir = os.path.join(config_dir, pybuilddir) - nsymbol = 0 - for name in os.listdir(builddir): - if not name.endswith(".so"): - continue - if IGNORED_EXTENSION in name: - print() - print(f"Ignore extension: {name}") + builddir = config_dir / pybuilddir + result = [] + for path in sorted(builddir.glob('**/*.so')): + if path.stem == IGNORED_EXTENSION: continue + result.append(Library(path, is_dynamic=True)) - print() - filename = os.path.join(builddir, name) - nsymbol += check_library(filename, dynamic=True) - - return nsymbol + return result def main(): - nsymbol = 0 + parser = argparse.ArgumentParser( + description=__doc__.split('\n', 1)[-1]) + parser.add_argument('-v', '--verbose', action='store_true', + help='be verbose (currently: print out all symbols)') + args = parser.parse_args() + + libraries = [] # static library - LIBRARY = sysconfig.get_config_var('LIBRARY') - if not LIBRARY: - raise Exception("failed to get LIBRARY variable from sysconfig") - if os.path.exists(LIBRARY): - nsymbol += check_library(LIBRARY) + try: + LIBRARY = pathlib.Path(sysconfig.get_config_var('LIBRARY')) + except TypeError as exc: + raise Exception("failed to get LIBRARY sysconfig variable") from exc + LIBRARY = pathlib.Path(LIBRARY) + if LIBRARY.exists(): + libraries.append(Library(LIBRARY, is_dynamic=False)) # dynamic library - LDLIBRARY = sysconfig.get_config_var('LDLIBRARY') - if not LDLIBRARY: - raise Exception("failed to get LDLIBRARY variable from sysconfig") + try: + LDLIBRARY = pathlib.Path(sysconfig.get_config_var('LDLIBRARY')) + except TypeError as exc: + raise Exception("failed to get LDLIBRARY sysconfig variable") from exc if LDLIBRARY != LIBRARY: - print() - nsymbol += check_library(LDLIBRARY, dynamic=True) + libraries.append(Library(LDLIBRARY, is_dynamic=True)) # Check extension modules like _ssl.cpython-310d-x86_64-linux-gnu.so - nsymbol += check_extensions() + libraries.extend(get_extension_libraries()) - if nsymbol: - print() - print(f"ERROR: Found {nsymbol} smelly symbols in total!") - sys.exit(1) + smelly_symbols = [] + for library in libraries: + symbols = get_exported_symbols(library) + if args.verbose: + print(f"{library.path}: {len(symbols)} symbol(s) found") + for symbol in sorted(symbols): + if args.verbose: + print(" -", symbol.name) + if symbol.is_smelly: + smelly_symbols.append(symbol) print() - print(f"OK: all exported symbols of all libraries " - f"are prefixed with {' or '.join(map(repr, ALLOWED_PREFIXES))}") + + if smelly_symbols: + print(f"Found {len(smelly_symbols)} smelly symbols in total!") + for symbol in sorted(smelly_symbols): + print(f" - {symbol.name} from {symbol.library.path}") + sys.exit(1) + + print(f"OK: all exported symbols of all libraries", + f"are prefixed with {' or '.join(map(repr, ALLOWED_PREFIXES))}", + f"or are covered by exceptions") if __name__ == "__main__": From 2f42f8334403bda2db98349518b51727269ec170 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 24 Jan 2026 02:19:01 +0900 Subject: [PATCH 059/133] gh-144005: Eliminate redundant refcounting in the JIT for BINARY_OP_EXTEND (#144006) --- Include/internal/pycore_opcode_metadata.h | 4 +-- Include/internal/pycore_uop_ids.h | 2 +- Include/internal/pycore_uop_metadata.h | 8 ++--- Lib/test/test_capi/test_opt.py | 17 +++++++++ ...-01-19-01-26-12.gh-issue-144005.Z3O33m.rst | 1 + Modules/_testinternalcapi/test_cases.c.h | 36 ++++++++++++------- Python/bytecodes.c | 13 ++++--- Python/executor_cases.c.h | 24 ++++++------- Python/generated_cases.c.h | 36 ++++++++++++------- Python/optimizer_bytecodes.c | 6 ++++ Python/optimizer_cases.c.h | 15 ++++++-- 11 files changed, 109 insertions(+), 53 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-26-12.gh-issue-144005.Z3O33m.rst diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index ce6324d0a8e..80c11b753be 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1094,7 +1094,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [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 | HAS_ERROR_NO_POP_FLAG }, - [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_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 }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, @@ -1347,7 +1347,7 @@ _PyOpcode_macro_expansion[256] = { [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 = 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_EXTEND] = { .nuops = 4, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, [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 } } }, [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 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 5cda407ba89..ccdcc27f903 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -389,7 +389,7 @@ extern "C" { #define _BINARY_OP_ADD_UNICODE_r03 586 #define _BINARY_OP_ADD_UNICODE_r13 587 #define _BINARY_OP_ADD_UNICODE_r23 588 -#define _BINARY_OP_EXTEND_r21 589 +#define _BINARY_OP_EXTEND_r23 589 #define _BINARY_OP_INPLACE_ADD_UNICODE_r21 590 #define _BINARY_OP_MULTIPLY_FLOAT_r03 591 #define _BINARY_OP_MULTIPLY_FLOAT_r13 592 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index c2e0f4a2c39..d51ed9c697a 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -115,7 +115,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_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_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_BINARY_OP_EXTEND] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, @@ -1113,7 +1113,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .entries = { { -1, -1, -1 }, { -1, -1, -1 }, - { 1, 2, _BINARY_OP_EXTEND_r21 }, + { 3, 2, _BINARY_OP_EXTEND_r23 }, { -1, -1, -1 }, }, }, @@ -3670,7 +3670,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_BINARY_OP_ADD_UNICODE_r23] = _BINARY_OP_ADD_UNICODE, [_BINARY_OP_INPLACE_ADD_UNICODE_r21] = _BINARY_OP_INPLACE_ADD_UNICODE, [_GUARD_BINARY_OP_EXTEND_r22] = _GUARD_BINARY_OP_EXTEND, - [_BINARY_OP_EXTEND_r21] = _BINARY_OP_EXTEND, + [_BINARY_OP_EXTEND_r23] = _BINARY_OP_EXTEND, [_BINARY_SLICE_r31] = _BINARY_SLICE, [_STORE_SLICE_r30] = _STORE_SLICE, [_BINARY_OP_SUBSCR_LIST_INT_r23] = _BINARY_OP_SUBSCR_LIST_INT, @@ -4239,7 +4239,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_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_EXTEND_r23] = "_BINARY_OP_EXTEND_r23", [_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE", [_BINARY_OP_INPLACE_ADD_UNICODE_r21] = "_BINARY_OP_INPLACE_ADD_UNICODE_r21", [_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 7c33320e9f1..5a0a379e31a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2897,6 +2897,23 @@ def testfunc(n): self.assertIn("_POP_TOP_NOP", uops) self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_binary_op_extend_float_long_add_refcount_elimination(self): + def testfunc(n): + a = 1.5 + b = 2 + res = 0.0 + for _ in range(n): + res = a + b + return res + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 3.5) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP_EXTEND", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_remove_guard_for_slice_list(self): def f(n): for i in range(n): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-26-12.gh-issue-144005.Z3O33m.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-26-12.gh-issue-144005.Z3O33m.rst new file mode 100644 index 00000000000..b3582197f45 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-26-12.gh-issue-144005.Z3O33m.rst @@ -0,0 +1 @@ +Eliminate redundant refcounting from ``BINARY_OP_EXTEND``. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index c02d236fc3e..a7d589dbe7b 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -317,6 +317,9 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef value; /* Skip 1 cache entry */ // _GUARD_BINARY_OP_EXTEND { @@ -348,25 +351,32 @@ STAT_INC(BINARY_OP, hit); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = d->action(left_o, right_o); - _PyStackRef tmp = right; - right = PyStackRef_NULL; - stack_pointer[-1] = right; - PyStackRef_CLOSE(tmp); - tmp = left; - left = PyStackRef_NULL; - stack_pointer[-2] = left; - PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); + l = left; + r = right; + } + // _POP_TOP + { + value = r; + stack_pointer[-2] = res; + stack_pointer[-1] = l; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = l; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); } - stack_pointer[0] = res; - stack_pointer += 1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index cef368e9b07..36df991e84d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -829,7 +829,7 @@ dummy_func( DEOPT_IF(!res); } - op(_BINARY_OP_EXTEND, (descr/4, left, right -- res)) { + op(_BINARY_OP_EXTEND, (descr/4, left, right -- res, l, r)) { PyObject *left_o = PyStackRef_AsPyObjectBorrow(left); PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); assert(INLINE_CACHE_ENTRIES_BINARY_OP == 5); @@ -838,13 +838,18 @@ dummy_func( STAT_INC(BINARY_OP, hit); PyObject *res_o = d->action(left_o, right_o); - DECREF_INPUTS(); - ERROR_IF(res_o == NULL); + if (res_o == NULL) { + ERROR_NO_POP(); + } res = PyStackRef_FromPyObjectSteal(res_o); + l = left; + r = right; + DEAD(left); + DEAD(right); } macro(BINARY_OP_EXTEND) = - unused/1 + _GUARD_BINARY_OP_EXTEND + rewind/-4 + _BINARY_OP_EXTEND; + unused/1 + _GUARD_BINARY_OP_EXTEND + rewind/-4 + _BINARY_OP_EXTEND + POP_TOP + POP_TOP; macro(BINARY_OP_INPLACE_ADD_UNICODE) = _GUARD_TOS_UNICODE + _GUARD_NOS_UNICODE + unused/5 + _BINARY_OP_INPLACE_ADD_UNICODE; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 4d4084971c7..9098bd219ed 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5143,12 +5143,14 @@ break; } - case _BINARY_OP_EXTEND_r21: { + case _BINARY_OP_EXTEND_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; @@ -5165,26 +5167,20 @@ ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = d->action(left_o, right_o); - _PyStackRef tmp = right; - right = PyStackRef_NULL; - stack_pointer[-1] = right; - PyStackRef_CLOSE(tmp); - tmp = left; - left = PyStackRef_NULL; - stack_pointer[-2] = left; - PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { 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; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - 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; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 194fbe4f268..9df6b2f70f9 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -317,6 +317,9 @@ _PyStackRef left; _PyStackRef right; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef value; /* Skip 1 cache entry */ // _GUARD_BINARY_OP_EXTEND { @@ -348,25 +351,32 @@ STAT_INC(BINARY_OP, hit); _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = d->action(left_o, right_o); - _PyStackRef tmp = right; - right = PyStackRef_NULL; - stack_pointer[-1] = right; - PyStackRef_CLOSE(tmp); - tmp = left; - left = PyStackRef_NULL; - stack_pointer[-2] = left; - PyStackRef_CLOSE(tmp); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); + l = left; + r = right; + } + // _POP_TOP + { + value = r; + stack_pointer[-2] = res; + stack_pointer[-1] = l; + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = l; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); } - 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 1584e731d1b..de7a2313f92 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -311,6 +311,12 @@ dummy_func(void) { r = right; } + op(_BINARY_OP_EXTEND, (left, right -- res, l, r)) { + res = sym_new_not_null(ctx); + l = left; + r = right; + } + op(_BINARY_OP_INPLACE_ADD_UNICODE, (left, right -- res)) { if (sym_is_const(ctx, left) && sym_is_const(ctx, right)) { assert(PyUnicode_CheckExact(sym_get_const(ctx, left))); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 341805d51e2..5fca6946266 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -882,11 +882,22 @@ } case _BINARY_OP_EXTEND: { + JitOptRef right; + JitOptRef left; JitOptRef res; + JitOptRef l; + JitOptRef r; + right = stack_pointer[-1]; + left = stack_pointer[-2]; + PyObject *descr = (PyObject *)this_instr->operand0; res = sym_new_not_null(ctx); - 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 25a10b60b04ab2fa802409dc6f211cf2ca028a0a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 23 Jan 2026 20:55:48 +0200 Subject: [PATCH 060/133] gh-144027: Fix documentation for ignorechars in base64.a85decode() (GH-144028) It does not support an ASCII string. Also add more tests. --- Doc/library/base64.rst | 3 +-- Lib/test/test_base64.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 3e7884debd5..64d66fcf6bd 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -254,8 +254,7 @@ Refer to the documentation of the individual functions for more information. *adobe* controls whether the input sequence is in Adobe Ascii85 format (i.e. is framed with <~ and ~>). - *ignorechars* should be a :term:`bytes-like object` or ASCII string - containing characters to ignore + *ignorechars* should be a byte string containing characters to ignore from the input. This should only contain whitespace characters, and by default contains all whitespace characters in ASCII. diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index d02992903f1..6e69ece8065 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -965,6 +965,19 @@ def test_a85decode_errors(self): self.assertRaises(ValueError, base64.a85decode, b'aaaay', foldspaces=True) + self.assertEqual(base64.a85decode(b"a b\nc", ignorechars=b" \n"), + b'\xc9\x89') + with self.assertRaises(ValueError): + base64.a85decode(b"a b\nc", ignorechars=b"") + with self.assertRaises(ValueError): + base64.a85decode(b"a b\nc", ignorechars=b" ") + with self.assertRaises(ValueError): + base64.a85decode(b"a b\nc", ignorechars=b"\n") + with self.assertRaises(TypeError): + base64.a85decode(b"a b\nc", ignorechars=" \n") + with self.assertRaises(TypeError): + base64.a85decode(b"a b\nc", ignorechars=None) + def test_b85decode_errors(self): illegal = list(range(33)) + \ list(b'"\',./:[\\]') + \ From 58ccf21cbb92e0e99cbe28f93f1a4a1f09af71ec Mon Sep 17 00:00:00 2001 From: Zachary Ware Date: Fri, 23 Jan 2026 15:07:27 -0600 Subject: [PATCH 061/133] gh-74902: Avoid hitting unicode.org for test data (GH-144195) Use our own pythontest.net instead. --- Lib/test/test_unicodedata.py | 56 +++++++++++++++--------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index f9c0cd20438..a46ca034f3b 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -30,6 +30,26 @@ def iterallchars(): maxunicode = 0xffff if quicktest else sys.maxunicode return map(chr, range(maxunicode + 1)) + +def check_version(testfile): + hdr = testfile.readline() + return unicodedata.unidata_version in hdr + + +def download_test_data_file(filename): + TESTDATAURL = f"http://www.pythontest.net/unicode/{unicodedata.unidata_version}/{filename}" + + try: + return open_urlresource(TESTDATAURL, encoding="utf-8", check=check_version) + except PermissionError: + raise unittest.SkipTest( + f"Permission error when downloading {TESTDATAURL} " + f"into the test data directory" + ) + except (OSError, HTTPException) as exc: + raise unittest.SkipTest(f"Failed to download {TESTDATAURL}: {exc}") + + class UnicodeMethodsTest(unittest.TestCase): # update this, if the database changes @@ -956,11 +976,6 @@ def test_segment_object(self): class NormalizationTest(unittest.TestCase): - @staticmethod - def check_version(testfile): - hdr = testfile.readline() - return unicodedata.unidata_version in hdr - @staticmethod def unistr(data): data = [int(x, 16) for x in data.split(" ")] @@ -970,17 +985,7 @@ def unistr(data): @requires_resource('cpu') def test_normalization(self): TESTDATAFILE = "NormalizationTest.txt" - TESTDATAURL = f"http://www.pythontest.net/unicode/{unicodedata.unidata_version}/{TESTDATAFILE}" - - # Hit the exception early - try: - testdata = open_urlresource(TESTDATAURL, encoding="utf-8", - check=self.check_version) - except PermissionError: - self.skipTest(f"Permission error when downloading {TESTDATAURL} " - f"into the test data directory") - except (OSError, HTTPException) as exc: - self.skipTest(f"Failed to download {TESTDATAURL}: {exc}") + testdata = download_test_data_file(TESTDATAFILE) with testdata: self.run_normalization_tests(testdata, unicodedata) @@ -1077,25 +1082,10 @@ class MyStr(str): class GraphemeBreakTest(unittest.TestCase): - @staticmethod - def check_version(testfile): - hdr = testfile.readline() - return unicodedata.unidata_version in hdr - @requires_resource('network') def test_grapheme_break(self): - TESTDATAFILE = "auxiliary/GraphemeBreakTest.txt" - TESTDATAURL = f"https://www.unicode.org/Public/{unicodedata.unidata_version}/ucd/{TESTDATAFILE}" - - # Hit the exception early - try: - testdata = open_urlresource(TESTDATAURL, encoding="utf-8", - check=self.check_version) - except PermissionError: - self.skipTest(f"Permission error when downloading {TESTDATAURL} " - f"into the test data directory") - except (OSError, HTTPException) as exc: - self.skipTest(f"Failed to download {TESTDATAURL}: {exc}") + TESTDATAFILE = "GraphemeBreakTest.txt" + testdata = download_test_data_file(TESTDATAFILE) with testdata: self.run_grapheme_break_tests(testdata) From 29f1e778faaa31479e4ef84e2fb37a7a53984550 Mon Sep 17 00:00:00 2001 From: Terry Jan Reedy Date: Fri, 23 Jan 2026 21:34:41 -0500 Subject: [PATCH 062/133] gh-135142: Initial 3.15 IDLE News3.txt entries (#144200) --- Lib/idlelib/News3.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt index 53d83762f99..0f61da8368f 100644 --- a/Lib/idlelib/News3.txt +++ b/Lib/idlelib/News3.txt @@ -1,9 +1,20 @@ +What's New in IDLE 3.15.0 +(since 3.14.0) +Released on 2026-10-01 +========================= + + +gh-143774: Better explain the operation of Format / Format Paragraph. +Patch by Terry J. Reedy. + +gh-139742: Colorize t-string prefixes for template strings in IDLE, +as done for f-string prefixes. Patch by Anuradha Agrawal. + What's New in IDLE 3.14.0 (since 3.13.0) Released on 2025-10-07 ========================= - gh-129873: Simplify displaying the IDLE doc by only copying the text section of idle.html to idlelib/help.html. Patch by Stan Ulbrych. From 4e10fa993a8bbc4d6e77910cb5fd1bc28473e8ec Mon Sep 17 00:00:00 2001 From: AN Long Date: Sat, 24 Jan 2026 18:35:32 +0900 Subject: [PATCH 063/133] gh-144007: Eliminate redundant refcounting in the JIT for BINARY_OP (GH-144011) --- 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 | 23 ++++++++++++++++ ...-01-19-01-56-44.gh-issue-144007.1xjdBf.rst | 1 + Modules/_testinternalcapi/test_cases.c.h | 27 +++++++++++++------ Python/bytecodes.c | 9 ++++--- Python/executor_cases.c.h | 26 +++++++----------- Python/generated_cases.c.h | 27 +++++++++++++------ Python/optimizer_bytecodes.c | 4 ++- Python/optimizer_cases.c.h | 26 +++++++++++++----- 11 files changed, 105 insertions(+), 48 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-56-44.gh-issue-144007.1xjdBf.rst diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 80c11b753be..95dee5d3526 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1343,7 +1343,7 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256]; #ifdef NEED_OPCODE_METADATA const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { - [BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 } } }, + [BINARY_OP] = { .nuops = 3, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _POP_TOP, 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 = 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 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index ccdcc27f903..8aa42933ec8 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -379,7 +379,7 @@ extern "C" { #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE #define MAX_UOP_ID 578 -#define _BINARY_OP_r21 579 +#define _BINARY_OP_r23 579 #define _BINARY_OP_ADD_FLOAT_r03 580 #define _BINARY_OP_ADD_FLOAT_r13 581 #define _BINARY_OP_ADD_FLOAT_r23 582 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index d51ed9c697a..f9f22ba0481 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -2931,7 +2931,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .entries = { { -1, -1, -1 }, { -1, -1, -1 }, - { 1, 2, _BINARY_OP_r21 }, + { 3, 2, _BINARY_OP_r23 }, { -1, -1, -1 }, }, }, @@ -4031,7 +4031,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_COPY_3_r23] = _COPY_3, [_COPY_3_r33] = _COPY_3, [_COPY_r01] = _COPY, - [_BINARY_OP_r21] = _BINARY_OP, + [_BINARY_OP_r23] = _BINARY_OP, [_SWAP_2_r02] = _SWAP_2, [_SWAP_2_r12] = _SWAP_2, [_SWAP_2_r22] = _SWAP_2, @@ -4225,7 +4225,7 @@ const uint16_t _PyUop_SpillsAndReloads[4][4] = { const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_BINARY_OP] = "_BINARY_OP", - [_BINARY_OP_r21] = "_BINARY_OP_r21", + [_BINARY_OP_r23] = "_BINARY_OP_r23", [_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT", [_BINARY_OP_ADD_FLOAT_r03] = "_BINARY_OP_ADD_FLOAT_r03", [_BINARY_OP_ADD_FLOAT_r13] = "_BINARY_OP_ADD_FLOAT_r13", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 5a0a379e31a..da0d4078c9f 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2897,6 +2897,29 @@ def testfunc(n): self.assertIn("_POP_TOP_NOP", uops) self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_binary_op_refcount_elimination(self): + class CustomAdder: + def __init__(self, val): + self.val = val + def __add__(self, other): + return CustomAdder(self.val + other.val) + + def testfunc(n): + a = CustomAdder(1) + b = CustomAdder(2) + res = None + for _ in range(n): + res = a + b + return res.val if res else 0 + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 3) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_BINARY_OP", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_binary_op_extend_float_long_add_refcount_elimination(self): def testfunc(n): a = 1.5 diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-56-44.gh-issue-144007.1xjdBf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-56-44.gh-issue-144007.1xjdBf.rst new file mode 100644 index 00000000000..26db86fae6b --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-19-01-56-44.gh-issue-144007.1xjdBf.rst @@ -0,0 +1 @@ +Eliminate redundant refcounting in the JIT for ``BINARY_OP``. diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index a7d589dbe7b..3c9eb919436 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -32,6 +32,9 @@ _PyStackRef lhs; _PyStackRef rhs; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef value; // _SPECIALIZE_BINARY_OP { rhs = stack_pointer[-1]; @@ -65,18 +68,26 @@ JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); + l = lhs; + r = rhs; + } + // _POP_TOP + { + value = r; + stack_pointer[-2] = res; + stack_pointer[-1] = l; _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = lhs; - lhs = res; - stack_pointer[-2] = lhs; - PyStackRef_CLOSE(tmp); - tmp = rhs; - rhs = PyStackRef_NULL; - stack_pointer[-1] = rhs; - PyStackRef_CLOSE(tmp); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = l; 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/bytecodes.c b/Python/bytecodes.c index 36df991e84d..bec03119993 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5119,7 +5119,7 @@ dummy_func( assert(oparg <= NB_OPARG_LAST); } - op(_BINARY_OP, (lhs, rhs -- res)) { + op(_BINARY_OP, (lhs, rhs -- res, l, r)) { PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs); @@ -5129,10 +5129,13 @@ dummy_func( ERROR_NO_POP(); } res = PyStackRef_FromPyObjectSteal(res_o); - DECREF_INPUTS(); + l = lhs; + r = rhs; + DEAD(lhs); + DEAD(rhs); } - macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP; + macro(BINARY_OP) = _SPECIALIZE_BINARY_OP + unused/4 + _BINARY_OP + POP_TOP + POP_TOP; pure replicate(2:4) inst(SWAP, (bottom, unused[oparg-2], top -- bottom, unused[oparg-2], top)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9098bd219ed..f51466abea9 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -16594,12 +16594,14 @@ break; } - case _BINARY_OP_r21: { + case _BINARY_OP_r23: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef rhs; _PyStackRef lhs; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; oparg = CURRENT_OPARG(); @@ -16620,23 +16622,13 @@ JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = lhs; - lhs = res; - stack_pointer[-2] = lhs; - PyStackRef_CLOSE(tmp); - tmp = rhs; - rhs = PyStackRef_NULL; - stack_pointer[-1] = rhs; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + l = lhs; + r = rhs; + _tos_cache2 = r; + _tos_cache1 = l; _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 9df6b2f70f9..ae9e1e5421b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -32,6 +32,9 @@ _PyStackRef lhs; _PyStackRef rhs; _PyStackRef res; + _PyStackRef l; + _PyStackRef r; + _PyStackRef value; // _SPECIALIZE_BINARY_OP { rhs = stack_pointer[-1]; @@ -65,18 +68,26 @@ JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(res_o); + l = lhs; + r = rhs; + } + // _POP_TOP + { + value = r; + stack_pointer[-2] = res; + stack_pointer[-1] = l; _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = lhs; - lhs = res; - stack_pointer[-2] = lhs; - PyStackRef_CLOSE(tmp); - tmp = rhs; - rhs = PyStackRef_NULL; - stack_pointer[-1] = rhs; - PyStackRef_CLOSE(tmp); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = l; 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 de7a2313f92..27b974f372d 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -211,7 +211,9 @@ dummy_func(void) { sym_set_type(left, &PyFloat_Type); } - op(_BINARY_OP, (lhs, rhs -- res)) { + op(_BINARY_OP, (lhs, rhs -- res, l, r)) { + l = lhs; + r = rhs; REPLACE_OPCODE_IF_EVALUATES_PURE(lhs, rhs, res); bool lhs_int = sym_matches_type(lhs, &PyLong_Type); bool rhs_int = sym_matches_type(rhs, &PyLong_Type); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 5fca6946266..3b25533e07f 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3616,8 +3616,12 @@ JitOptRef rhs; JitOptRef lhs; JitOptRef res; + JitOptRef l; + JitOptRef r; rhs = stack_pointer[-1]; lhs = stack_pointer[-2]; + l = lhs; + r = rhs; if ( sym_is_safe_const(ctx, lhs) && sym_is_safe_const(ctx, rhs) @@ -3627,6 +3631,8 @@ _PyStackRef lhs = sym_get_const_as_stackref(ctx, lhs_sym); _PyStackRef rhs = sym_get_const_as_stackref(ctx, rhs_sym); _PyStackRef res_stackref; + _PyStackRef l_stackref; + _PyStackRef r_stackref; /* Start of uop copied from bytecodes for constant evaluation */ PyObject *lhs_o = PyStackRef_AsPyObjectBorrow(lhs); PyObject *rhs_o = PyStackRef_AsPyObjectBorrow(rhs); @@ -3636,18 +3642,24 @@ JUMP_TO_LABEL(error); } res_stackref = PyStackRef_FromPyObjectSteal(res_o); + l_stackref = lhs; + r_stackref = rhs; /* End of uop copied from bytecodes for constant evaluation */ + (void)l_stackref; + (void)r_stackref; 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 - ADD_OP(_POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); + // Replace with _INSERT_2_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result + ADD_OP(_INSERT_2_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result); } } - CHECK_STACK_BOUNDS(-1); + 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; } @@ -3684,9 +3696,11 @@ else { res = sym_new_type(ctx, &PyFloat_Type); } - CHECK_STACK_BOUNDS(-1); + 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 ca99bfdefb7093d9287353b7d1db97222a414b0e Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sat, 24 Jan 2026 17:36:40 +0800 Subject: [PATCH 064/133] gh-144016: Fix bad stack assert in the JIT optimizer (GH-144019) --- Python/optimizer_analysis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index c6a1ae60a31..6c381ab184f 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -507,7 +507,7 @@ optimize_uops( *(ctx->out_buffer.next++) = *this_instr; } assert(ctx->frame != NULL); - if (!CURRENT_FRAME_IS_INIT_SHIM()) { + if (!CURRENT_FRAME_IS_INIT_SHIM() && !ctx->done) { DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); ctx->frame->stack_pointer = stack_pointer; assert(STACK_LEVEL() >= 0); From 6f579147e35f85d74c262719c6cac7277f96b124 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Sat, 24 Jan 2026 17:37:45 +0800 Subject: [PATCH 065/133] Misc: remove duplicate `instr_frame` assignment in `_PyJit_TryInitializeTracing` (GH-144155) Remove duplicate instr_frame assignment in optimizer --- Python/optimizer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index f25242972ef..b8208c7d888 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1050,7 +1050,6 @@ _PyJit_TryInitializeTracing( tracer->initial_state.exit = exit; tracer->initial_state.stack_depth = curr_stackdepth; tracer->initial_state.chain_depth = chain_depth; - tracer->prev_state.instr_frame = frame; tracer->prev_state.dependencies_still_valid = true; tracer->prev_state.instr_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame)); tracer->prev_state.instr = curr_instr; From 29840247ff6da36808cd04115421ff59cdaea455 Mon Sep 17 00:00:00 2001 From: Hai Zhu Date: Sat, 24 Jan 2026 17:43:01 +0800 Subject: [PATCH 066/133] gh-144068: fix JIT tracer memory leak when daemon thread exits (GH-144077) --- Lib/test/test_capi/test_opt.py | 23 +++++++++++++++++++ ...-01-21-02-30-06.gh-issue-144068.9TTu7v.rst | 1 + Python/pystate.c | 4 ++++ 3 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index da0d4078c9f..f2249847775 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3889,6 +3889,29 @@ def __next__(self): """), PYTHON_JIT="1", PYTHON_JIT_STRESS="1") self.assertEqual(result[0].rc, 0, result) + def test_144068_daemon_thread_jit_cleanup(self): + result = script_helper.run_python_until_end('-c', textwrap.dedent(""" + import threading + import time + + def hot_loop(): + end = time.time() + 5.0 + while time.time() < end: + pass + + # Create a daemon thread that will be abandoned at shutdown + t = threading.Thread(target=hot_loop, daemon=True) + t.start() + + time.sleep(0.1) + """), PYTHON_JIT="1", ASAN_OPTIONS="detect_leaks=1") + self.assertEqual(result[0].rc, 0, result) + stderr = result[0].err.decode('utf-8', errors='replace') + self.assertNotIn('LeakSanitizer', stderr, + f"Memory leak detected by ASan:\n{stderr}") + self.assertNotIn('_PyJit_TryInitializeTracing', stderr, + f"JIT tracer memory leak detected:\n{stderr}") + def global_identity(x): return x diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst new file mode 100644 index 00000000000..b3e5db64a36 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-21-02-30-06.gh-issue-144068.9TTu7v.rst @@ -0,0 +1 @@ +Fix JIT tracer memory leak, ensure the JIT tracer state is freed when daemon threads are cleaned up during interpreter shutdown. diff --git a/Python/pystate.c b/Python/pystate.c index 19f1245d60a..a8f37bedc81 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1843,6 +1843,10 @@ PyThreadState_Clear(PyThreadState *tstate) _PyThreadState_ClearMimallocHeaps(tstate); +#ifdef _Py_TIER2 + _PyJit_TracerFree((_PyThreadStateImpl *)tstate); +#endif + tstate->_status.cleared = 1; // XXX Call _PyThreadStateSwap(runtime, NULL) here if "current". From 6d972e0104097e476118686ff7c84ea238ecafc3 Mon Sep 17 00:00:00 2001 From: reiden <65756407+reidenong@users.noreply.github.com> Date: Sat, 24 Jan 2026 18:02:08 +0800 Subject: [PATCH 067/133] gh-130415: Narrow types to constants in branches involving specialized comparisons with a constant (GH-144150) --- Include/internal/pycore_optimizer_types.h | 2 + Lib/test/test_capi/test_opt.py | 132 ++++++++++++++++++ Python/optimizer_analysis.c | 5 + Python/optimizer_bytecodes.c | 36 ++++- Python/optimizer_cases.c.h | 33 ++++- Python/optimizer_symbols.c | 160 +++++++++++++++++++++- 6 files changed, 360 insertions(+), 8 deletions(-) diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index a879ca26ce7..b4b93e83538 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -76,6 +76,8 @@ typedef struct { typedef enum { JIT_PRED_IS, JIT_PRED_IS_NOT, + JIT_PRED_EQ, + JIT_PRED_NE, } JitOptPredicateKind; typedef struct { diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index f2249847775..ff3adb1d454 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -890,6 +890,138 @@ def testfunc(n): self.assertLessEqual(len(guard_nos_unicode_count), 1) self.assertIn("_COMPARE_OP_STR", uops) + def test_compare_int_eq_narrows_to_constant(self): + def f(n): + def return_1(): + return 1 + + hits = 0 + v = return_1() + for _ in range(n): + if v == 1: + if v == 1: + hits += 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_INT"), 1) + + def test_compare_int_ne_narrows_to_constant(self): + def f(n): + def return_1(): + return 1 + + hits = 0 + v = return_1() + for _ in range(n): + if v != 1: + hits += 1000 + else: + if v == 1: + hits += v + 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD * 2) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_INT"), 1) + + def test_compare_float_eq_narrows_to_constant(self): + def f(n): + def return_tenth(): + return 0.1 + + hits = 0 + v = return_tenth() + for _ in range(n): + if v == 0.1: + if v == 0.1: + hits += 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1) + + def test_compare_float_ne_narrows_to_constant(self): + def f(n): + def return_tenth(): + return 0.1 + + hits = 0 + v = return_tenth() + for _ in range(n): + if v != 0.1: + hits += 1000 + else: + if v == 0.1: + hits += 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_FLOAT"), 1) + + def test_compare_str_eq_narrows_to_constant(self): + def f(n): + def return_hello(): + return "hello" + + hits = 0 + v = return_hello() + for _ in range(n): + if v == "hello": + if v == "hello": + hits += 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) + + def test_compare_str_ne_narrows_to_constant(self): + def f(n): + def return_hello(): + return "hello" + + hits = 0 + v = return_hello() + for _ in range(n): + if v != "hello": + hits += 1000 + else: + if v == "hello": + hits += 1 + return hits + + res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + # Constant narrowing allows constant folding for second comparison + self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) + @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_sequential(self): def dummy12(x): diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 6c381ab184f..65c9239f1ff 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -250,6 +250,11 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing +/* Comparison oparg masks */ +#define COMPARE_LT_MASK 2 +#define COMPARE_GT_MASK 4 +#define COMPARE_EQ_MASK 8 + #define JUMP_TO_LABEL(label) goto label; static int diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 27b974f372d..38cd088d9fb 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -521,21 +521,51 @@ dummy_func(void) { } op(_COMPARE_OP_INT, (left, right -- res, l, r)) { - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res); } op(_COMPARE_OP_FLOAT, (left, right -- res, l, r)) { - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res); } op(_COMPARE_OP_STR, (left, right -- res, l, r)) { - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; REPLACE_OPCODE_IF_EVALUATES_PURE(left, right, res); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 3b25533e07f..e9405473fe2 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2118,7 +2118,16 @@ JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; if ( @@ -2178,7 +2187,16 @@ JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; if ( @@ -2242,7 +2260,16 @@ JitOptRef r; right = stack_pointer[-1]; left = stack_pointer[-2]; - res = sym_new_type(ctx, &PyBool_Type); + int cmp_mask = oparg & (COMPARE_LT_MASK | COMPARE_GT_MASK | COMPARE_EQ_MASK); + if (cmp_mask == COMPARE_EQ_MASK) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_EQ); + } + else if (cmp_mask == (COMPARE_LT_MASK | COMPARE_GT_MASK)) { + res = sym_new_predicate(ctx, left, right, JIT_PRED_NE); + } + else { + res = sym_new_type(ctx, &PyBool_Type); + } l = left; r = right; if ( diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index a9640aaa507..51cf6e189f0 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -875,9 +875,11 @@ _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef ref, bool br bool narrow = false; switch(pred.kind) { + case JIT_PRED_EQ: case JIT_PRED_IS: narrow = branch_is_true; break; + case JIT_PRED_NE: case JIT_PRED_IS_NOT: narrow = !branch_is_true; break; @@ -1300,11 +1302,11 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (None)"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == Py_None, "predicate narrowing did not narrow subject to None"); - // Test narrowing subject to numerical constant + // Test narrowing subject to numerical constant from is comparison subject = _Py_uop_sym_new_unknown(ctx); PyObject *one_obj = PyLong_FromLong(1); JitOptRef const_one = _Py_uop_sym_new_const(ctx, one_obj); - if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(const_one)) { + if (PyJitRef_IsNull(subject) || one_obj == NULL || PyJitRef_IsNull(const_one)) { goto fail; } ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_IS); @@ -1315,6 +1317,160 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1"); + // Test narrowing subject to constant from EQ predicate for int + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1"); + + // Resolving EQ predicate to False should not narrow subject for int + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to constant from NE predicate for int + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (1)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == one_obj, "predicate narrowing did not narrow subject to 1"); + + // Resolving NE predicate to true should not narrow subject for int + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_one, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to constant from EQ predicate for float + subject = _Py_uop_sym_new_unknown(ctx); + PyObject *float_tenth_obj = PyFloat_FromDouble(0.1); + JitOptRef const_float_tenth = _Py_uop_sym_new_const(ctx, float_tenth_obj); + if (PyJitRef_IsNull(subject) || float_tenth_obj == NULL || PyJitRef_IsNull(const_float_tenth)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (float)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == float_tenth_obj, "predicate narrowing did not narrow subject to 0.1"); + + // Resolving EQ predicate to False should not narrow subject for float + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to constant from NE predicate for float + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (float)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == float_tenth_obj, "predicate narrowing did not narrow subject to 0.1"); + + // Resolving NE predicate to true should not narrow subject for float + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_float_tenth, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to constant from EQ predicate for str + subject = _Py_uop_sym_new_unknown(ctx); + PyObject *str_hello_obj = PyUnicode_FromString("hello"); + JitOptRef const_str_hello = _Py_uop_sym_new_const(ctx, str_hello_obj); + if (PyJitRef_IsNull(subject) || str_hello_obj == NULL || PyJitRef_IsNull(const_str_hello)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (str)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == str_hello_obj, "predicate narrowing did not narrow subject to hello"); + + // Resolving EQ predicate to False should not narrow subject for str + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_EQ); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + + // Test narrowing subject to constant from NE predicate for str + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, false); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, subject), "predicate narrowing did not const-narrow subject (str)"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, subject) == str_hello_obj, "predicate narrowing did not narrow subject to hello"); + + // Resolving NE predicate to true should not narrow subject for str + subject = _Py_uop_sym_new_unknown(ctx); + if (PyJitRef_IsNull(subject)) { + goto fail; + } + ref = _Py_uop_sym_new_predicate(ctx, subject, const_str_hello, JIT_PRED_NE); + if (PyJitRef_IsNull(ref)) { + goto fail; + } + _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66)); if (val_big == NULL) { goto fail; From 5f736a0432c2e43de8f35d9a75aa814e4407e637 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 24 Jan 2026 11:19:21 +0100 Subject: [PATCH 068/133] gh-142913: Add generated test files to gitattributes (GH-144209) --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitattributes b/.gitattributes index e88d6ea13e2..14c1eced0cf 100644 --- a/.gitattributes +++ b/.gitattributes @@ -94,6 +94,8 @@ Lib/test/test_stable_abi_ctypes.py generated Lib/test/test_zoneinfo/data/*.json generated Lib/token.py generated Misc/sbom.spdx.json generated +Modules/_testinternalcapi/test_cases.c.h generated +Modules/_testinternalcapi/test_targets.h generated Objects/typeslots.inc generated PC/python3dll.c generated Parser/parser.c generated From 012c498035a9adfe9fd218907db1550ecb057f77 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 24 Jan 2026 13:13:50 +0200 Subject: [PATCH 069/133] gh-142037: Improve error messages for printf-style formatting (GH-142081) This affects string formatting as well as bytes and bytearray formatting. * For errors in the format string, always include the position of the start of the format unit. * For errors related to the formatted arguments, always include the number or the name of the formatted argument. * Suggest more probable causes of errors in the format string (stray %, unsupported format, unexpected character). * Provide more information when the number of arguments does not match the number of format units. * Raise more specific errors when access of arguments by name is mixed with sequential access and when * is used with a mapping. * Add tests for some uncovered cases. --- Lib/test/test_bytes.py | 22 +- Lib/test/test_format.py | 239 ++++++++++++++--- Lib/test/test_peepholer.py | 19 +- Lib/test/test_str.py | 45 +++- ...-11-29-10-06-06.gh-issue-142037.OpIGzK.rst | 7 + Objects/bytesobject.c | 221 +++++++++++----- Objects/unicode_format.c | 245 +++++++++++++----- 7 files changed, 591 insertions(+), 207 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-10-06-06.gh-issue-142037.OpIGzK.rst diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index c42c0d4f5e9..742bad21a33 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -792,16 +792,16 @@ def __int__(self): pi = PseudoFloat(3.1415) exceptions_params = [ - ('%x format: an integer is required, not float', b'%x', 3.14), - ('%X format: an integer is required, not float', b'%X', 2.11), - ('%o format: an integer is required, not float', b'%o', 1.79), - ('%x format: an integer is required, not PseudoFloat', b'%x', pi), - ('%x format: an integer is required, not complex', b'%x', 3j), - ('%X format: an integer is required, not complex', b'%X', 2j), - ('%o format: an integer is required, not complex', b'%o', 1j), - ('%u format: a real number is required, not complex', b'%u', 3j), - ('%i format: a real number is required, not complex', b'%i', 2j), - ('%d format: a real number is required, not complex', b'%d', 2j), + ('%x requires an integer, not float', b'%x', 3.14), + ('%X requires an integer, not float', b'%X', 2.11), + ('%o requires an integer, not float', b'%o', 1.79), + (r'%x requires an integer, not .*\.PseudoFloat', b'%x', pi), + ('%x requires an integer, not complex', b'%x', 3j), + ('%X requires an integer, not complex', b'%X', 2j), + ('%o requires an integer, not complex', b'%o', 1j), + ('%u requires a real number, not complex', b'%u', 3j), + ('%i requires a real number, not complex', b'%i', 2j), + ('%d requires a real number, not complex', b'%d', 2j), ( r'%c requires an integer in range\(256\)' r' or a single byte, not .*\.PseudoFloat', @@ -810,7 +810,7 @@ def __int__(self): ] for msg, format_bytes, value in exceptions_params: - with self.assertRaisesRegex(TypeError, msg): + with self.assertRaisesRegex(TypeError, 'format argument: ' + msg): operator.mod(format_bytes, value) def test_memory_leak_gh_140939(self): diff --git a/Lib/test/test_format.py b/Lib/test/test_format.py index 1f626d87fa6..00f1ab44b0a 100644 --- a/Lib/test/test_format.py +++ b/Lib/test/test_format.py @@ -57,10 +57,6 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False): else: b_format = formatstr ba_format = bytearray(b_format) - b_args = [] - if not isinstance(args, tuple): - args = (args, ) - b_args = tuple(args) if output is None: b_output = ba_output = None else: @@ -69,8 +65,8 @@ def testcommon(formatstr, args, output=None, limit=None, overflowok=False): else: b_output = output ba_output = bytearray(b_output) - testformat(b_format, b_args, b_output, limit, overflowok) - testformat(ba_format, b_args, ba_output, limit, overflowok) + testformat(b_format, args, b_output, limit, overflowok) + testformat(ba_format, args, ba_output, limit, overflowok) def test_exc(formatstr, args, exception, excmsg): try: @@ -82,6 +78,7 @@ def test_exc(formatstr, args, exception, excmsg): else: if verbose: print('no') print('Unexpected ', exception, ':', repr(str(exc))) + raise except: if verbose: print('no') print('Unexpected exception') @@ -92,6 +89,8 @@ def test_exc(formatstr, args, exception, excmsg): def test_exc_common(formatstr, args, exception, excmsg): # test str and bytes test_exc(formatstr, args, exception, excmsg) + if isinstance(args, dict): + args = {k.encode('ascii'): v for k, v in args.items()} test_exc(formatstr.encode('ascii'), args, exception, excmsg) class FormatTest(unittest.TestCase): @@ -272,45 +271,154 @@ def test_common_format(self): if verbose: print('Testing exceptions') - test_exc_common('%', (), ValueError, "incomplete format") - test_exc_common('% %s', 1, ValueError, - "unsupported format character '%' (0x25) at index 2") + test_exc_common('abc %', (), ValueError, "stray % at position 4") + test_exc_common('abc % %s', 1, ValueError, + "stray % at position 4 or unexpected format character '%' at position 6") + test_exc_common('abc %z', 1, ValueError, + "unsupported format %z at position 4") + test_exc_common("abc %Id", 1, ValueError, + "unsupported format %I at position 4") + test_exc_common("abc %'d", 1, ValueError, + "stray % at position 4 or unexpected format character \"'\" at position 5") + test_exc_common("abc %1 d", 1, ValueError, + "stray % at position 4 or unexpected format character ' ' at position 6") + test_exc_common('abc % (x)r', {}, ValueError, + "stray % at position 4 or unexpected format character '(' at position 6") + test_exc_common('abc %((x)r', {}, ValueError, + "stray % or incomplete format key at position 4") + test_exc_common('%r %r', 1, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%r %r', (1,), TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%r', (), TypeError, + "not enough arguments for format string (got 0)") + test_exc_common('abc %' + '9'*50 + 'r', 1, ValueError, + "width too big at position 4") + test_exc_common('abc %.' + '9'*50 + 'r', 1, ValueError, + "precision too big at position 4") + test_exc_common('%r %*r', 1, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%r %*r', (1,), TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%*r', (1,), TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%*r', (), TypeError, + "not enough arguments for format string (got 0)") + test_exc_common('%r %.*r', 1, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%r %.*r', (1,), TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%.*r', (1,), TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%.*r', (), TypeError, + "not enough arguments for format string (got 0)") + test_exc_common('%(x)r', 1, TypeError, + "format requires a mapping, not int") + test_exc_common('%*r', 1, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%*r', 3.14, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%*r', (3.14, 1), TypeError, + "format argument 1: * requires int, not float") + test_exc_common('%.*r', 1, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%.*r', 3.14, TypeError, + "not enough arguments for format string (got 1)") + test_exc_common('%.*r', (3.14, 1), TypeError, + "format argument 1: * requires int, not float") + test_exc_common('%*r', (2**1000, 1), OverflowError, + "format argument 1: too big for width") + test_exc_common('%*r', (-2**1000, 1), OverflowError, + "format argument 1: too big for width") + test_exc_common('%.*r', (2**1000, 1), OverflowError, + "format argument 1: too big for precision") + test_exc_common('%.*r', (-2**1000, 1), OverflowError, + "format argument 1: too big for precision") test_exc_common('%d', '1', TypeError, - "%d format: a real number is required, not str") + "format argument: %d requires a real number, not str") test_exc_common('%d', b'1', TypeError, - "%d format: a real number is required, not bytes") + "format argument: %d requires a real number, not bytes") + test_exc_common('%d', ('1',), TypeError, + "format argument 1: %d requires a real number, not str") test_exc_common('%x', '1', TypeError, - "%x format: an integer is required, not str") + "format argument: %x requires an integer, not str") test_exc_common('%x', 3.14, TypeError, - "%x format: an integer is required, not float") + "format argument: %x requires an integer, not float") + test_exc_common('%x', ('1',), TypeError, + "format argument 1: %x requires an integer, not str") test_exc_common('%i', '1', TypeError, - "%i format: a real number is required, not str") + "format argument: %i requires a real number, not str") test_exc_common('%i', b'1', TypeError, - "%i format: a real number is required, not bytes") + "format argument: %i requires a real number, not bytes") + test_exc_common('%g', '1', TypeError, + "format argument: %g requires a real number, not str") + test_exc_common('%g', ('1',), TypeError, + "format argument 1: %g requires a real number, not str") def test_str_format(self): testformat("%r", "\u0378", "'\\u0378'") # non printable testformat("%a", "\u0378", "'\\u0378'") # non printable testformat("%r", "\u0374", "'\u0374'") # printable testformat("%a", "\u0374", "'\\u0374'") # printable + testformat('%(x)r', {'x': 1}, '1') # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') test_exc('abc %b', 1, ValueError, - "unsupported format character 'b' (0x62) at index 5") - #test_exc(unicode('abc %\u3000','raw-unicode-escape'), 1, ValueError, - # "unsupported format character '?' (0x3000) at index 5") - test_exc('%g', '1', TypeError, "must be real number, not str") + "unsupported format %b at position 4") + test_exc("abc %\nd", 1, ValueError, + "stray % at position 4 or unexpected format character U+000A at position 5") + test_exc("abc %\x1fd", 1, ValueError, + "stray % at position 4 or unexpected format character U+001F at position 5") + test_exc("abc %\x7fd", 1, ValueError, + "stray % at position 4 or unexpected format character U+007F at position 5") + test_exc("abc %\x80d", 1, ValueError, + "stray % at position 4 or unexpected format character U+0080 at position 5") + test_exc('abc %äd', 1, ValueError, + "stray % at position 4 or unexpected format character 'ä' (U+00E4) at position 5") + test_exc('abc %€d', 1, ValueError, + "stray % at position 4 or unexpected format character '€' (U+20AC) at position 5") test_exc('no format', '1', TypeError, - "not all arguments converted during string formatting") - test_exc('%c', -1, OverflowError, "%c arg not in range(0x110000)") + "not all arguments converted during string formatting (required 0, got 1)") + test_exc('%r', (1, 2), TypeError, + "not all arguments converted during string formatting (required 1, got 2)") + test_exc('%(x)r %r', {'x': 1}, ValueError, + "format requires a parenthesised mapping key at position 6") + test_exc('%(x)*r', {'x': 1}, ValueError, + "* cannot be used with a parenthesised mapping key at position 0") + test_exc('%(x).*r', {'x': 1}, ValueError, + "* cannot be used with a parenthesised mapping key at position 0") + test_exc('%(x)d', {'x': '1'}, TypeError, + "format argument 'x': %d requires a real number, not str") + test_exc('%(x)x', {'x': '1'}, TypeError, + "format argument 'x': %x requires an integer, not str") + test_exc('%(x)g', {'x': '1'}, TypeError, + "format argument 'x': %g requires a real number, not str") + test_exc('%c', -1, OverflowError, + "format argument: %c argument not in range(0x110000)") + test_exc('%c', (-1,), OverflowError, + "format argument 1: %c argument not in range(0x110000)") + test_exc('%(x)c', {'x': -1}, OverflowError, + "format argument 'x': %c argument not in range(0x110000)") test_exc('%c', sys.maxunicode+1, OverflowError, - "%c arg not in range(0x110000)") - #test_exc('%c', 2**128, OverflowError, "%c arg not in range(0x110000)") - test_exc('%c', 3.14, TypeError, "%c requires an int or a unicode character, not float") - test_exc('%c', 'ab', TypeError, "%c requires an int or a unicode character, not a string of length 2") - test_exc('%c', b'x', TypeError, "%c requires an int or a unicode character, not bytes") + "format argument: %c argument not in range(0x110000)") + test_exc('%c', 2**128, OverflowError, + "format argument: %c argument not in range(0x110000)") + test_exc('%c', 3.14, TypeError, + "format argument: %c requires an integer or a unicode character, not float") + test_exc('%c', (3.14,), TypeError, + "format argument 1: %c requires an integer or a unicode character, not float") + test_exc('%(x)c', {'x': 3.14}, TypeError, + "format argument 'x': %c requires an integer or a unicode character, not float") + test_exc('%c', 'ab', TypeError, + "format argument: %c requires an integer or a unicode character, not a string of length 2") + test_exc('%c', ('ab',), TypeError, + "format argument 1: %c requires an integer or a unicode character, not a string of length 2") + test_exc('%(x)c', {'x': 'ab'}, TypeError, + "format argument 'x': %c requires an integer or a unicode character, not a string of length 2") + test_exc('%c', b'x', TypeError, + "format argument: %c requires an integer or a unicode character, not bytes") if maxsize == 2**31-1: # crashes 2.2.1 and earlier: @@ -355,36 +463,83 @@ def __bytes__(self): testcommon(b"%r", b"ghi", b"b'ghi'") testcommon(b"%r", "jkl", b"'jkl'") testcommon(b"%r", "\u0544", b"'\\u0544'") + testcommon(b'%(x)r', {b'x': 1}, b'1') # Test exception for unknown format characters, etc. if verbose: print('Testing exceptions') - test_exc(b'%g', '1', TypeError, "float argument required, not str") - test_exc(b'%g', b'1', TypeError, "float argument required, not bytes") + test_exc(b"abc %\nd", 1, ValueError, + "stray % at position 4 or unexpected format character with code 0x0a at position 5") + test_exc(b"abc %'d", 1, ValueError, + "stray % at position 4 or unexpected format character \"'\" at position 5") + test_exc(b"abc %\x1fd", 1, ValueError, + "stray % at position 4 or unexpected format character with code 0x1f at position 5") + test_exc(b"abc %\x7fd", 1, ValueError, + "stray % at position 4 or unexpected format character with code 0x7f at position 5") + test_exc(b"abc %\x80d", 1, ValueError, + "stray % at position 4 or unexpected format character with code 0x80 at position 5") test_exc(b'no format', 7, TypeError, - "not all arguments converted during bytes formatting") + "not all arguments converted during bytes formatting (required 0, got 1)") test_exc(b'no format', b'1', TypeError, - "not all arguments converted during bytes formatting") + "not all arguments converted during bytes formatting (required 0, got 1)") test_exc(b'no format', bytearray(b'1'), TypeError, - "not all arguments converted during bytes formatting") + "not all arguments converted during bytes formatting (required 0, got 1)") + test_exc(b'%r', (1, 2), TypeError, + "not all arguments converted during bytes formatting (required 1, got 2)") + test_exc(b'%(x)r %r', {b'x': 1}, ValueError, + "format requires a parenthesised mapping key at position 6") + test_exc(b'%(x)*r', {b'x': 1}, ValueError, + "* cannot be used with a parenthesised mapping key at position 0") + test_exc(b'%(x).*r', {b'x': 1}, ValueError, + "* cannot be used with a parenthesised mapping key at position 0") + test_exc(b'%(x)d', {b'x': '1'}, TypeError, + "format argument b'x': %d requires a real number, not str") + test_exc(b'%(x)x', {b'x': '1'}, TypeError, + "format argument b'x': %x requires an integer, not str") + test_exc(b'%(x)g', {b'x': '1'}, TypeError, + "format argument b'x': %g requires a real number, not str") test_exc(b"%c", -1, OverflowError, - "%c arg not in range(256)") + "format argument: %c argument not in range(256)") + test_exc(b"%c", (-1,), OverflowError, + "format argument 1: %c argument not in range(256)") + test_exc(b"%(x)c", {b'x': -1}, OverflowError, + "format argument b'x': %c argument not in range(256)") test_exc(b"%c", 256, OverflowError, - "%c arg not in range(256)") + "format argument: %c argument not in range(256)") test_exc(b"%c", 2**128, OverflowError, - "%c arg not in range(256)") + "format argument: %c argument not in range(256)") test_exc(b"%c", b"Za", TypeError, - "%c requires an integer in range(256) or a single byte, not a bytes object of length 2") + "format argument: %c requires an integer in range(256) or a single byte, not a bytes object of length 2") + test_exc(b"%c", (b"Za",), TypeError, + "format argument 1: %c requires an integer in range(256) or a single byte, not a bytes object of length 2") + test_exc(b"%(x)c", {b'x': b"Za"}, TypeError, + "format argument b'x': %c requires an integer in range(256) or a single byte, not a bytes object of length 2") + test_exc(b"%c", bytearray(b"Za"), TypeError, + "format argument: %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") + test_exc(b"%c", (bytearray(b"Za"),), TypeError, + "format argument 1: %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") + test_exc(b"%(x)c", {b'x': bytearray(b"Za")}, TypeError, + "format argument b'x': %c requires an integer in range(256) or a single byte, not a bytearray object of length 2") test_exc(b"%c", "Y", TypeError, - "%c requires an integer in range(256) or a single byte, not str") + "format argument: %c requires an integer in range(256) or a single byte, not str") test_exc(b"%c", 3.14, TypeError, - "%c requires an integer in range(256) or a single byte, not float") + "format argument: %c requires an integer in range(256) or a single byte, not float") + test_exc(b"%c", (3.14,), TypeError, + "format argument 1: %c requires an integer in range(256) or a single byte, not float") + test_exc(b"%(x)c", {b'x': 3.14}, TypeError, + "format argument b'x': %c requires an integer in range(256) or a single byte, not float") test_exc(b"%b", "Xc", TypeError, - "%b requires a bytes-like object, " - "or an object that implements __bytes__, not 'str'") + "format argument: %b requires a bytes-like object, " + "or an object that implements __bytes__, not str") + test_exc(b"%b", ("Xc",), TypeError, + "format argument 1: %b requires a bytes-like object, " + "or an object that implements __bytes__, not str") + test_exc(b"%(x)b", {b'x': "Xc"}, TypeError, + "format argument b'x': %b requires a bytes-like object, " + "or an object that implements __bytes__, not str") test_exc(b"%s", "Wd", TypeError, - "%b requires a bytes-like object, " - "or an object that implements __bytes__, not 'str'") + "format argument: %b requires a bytes-like object, " + "or an object that implements __bytes__, not str") if maxsize == 2**31-1: # crashes 2.2.1 and earlier: @@ -626,7 +781,7 @@ def test_specifier_z_error(self): with self.assertRaisesRegex(ValueError, error_msg): f"{'x':zs}" # can't apply to string - error_msg = re.escape("unsupported format character 'z'") + error_msg = re.escape("unsupported format %z at position 0") with self.assertRaisesRegex(ValueError, error_msg): "%z.1f" % 0 # not allowed in old style string interpolation with self.assertRaisesRegex(ValueError, error_msg): diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 1caf6de4a14..88d20bbb028 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -733,22 +733,27 @@ def test_format_errors(self): with self.assertRaisesRegex(TypeError, 'not all arguments converted during string formatting'): eval("'%s' % (x, y)", {'x': 1, 'y': 2}) - with self.assertRaisesRegex(ValueError, 'incomplete format'): + with self.assertRaisesRegex(ValueError, 'stray % at position 2'): eval("'%s%' % (x,)", {'x': 1234}) - with self.assertRaisesRegex(ValueError, 'incomplete format'): + with self.assertRaisesRegex(ValueError, 'stray % at position 4'): eval("'%s%%%' % (x,)", {'x': 1234}) with self.assertRaisesRegex(TypeError, 'not enough arguments for format string'): eval("'%s%z' % (x,)", {'x': 1234}) - with self.assertRaisesRegex(ValueError, 'unsupported format character'): + with self.assertRaisesRegex(ValueError, + 'unsupported format %z at position 2'): eval("'%s%z' % (x, 5)", {'x': 1234}) - with self.assertRaisesRegex(TypeError, 'a real number is required, not str'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %d requires a real number, not str'): eval("'%d' % (x,)", {'x': '1234'}) - with self.assertRaisesRegex(TypeError, 'an integer is required, not float'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %x requires an integer, not float'): eval("'%x' % (x,)", {'x': 1234.56}) - with self.assertRaisesRegex(TypeError, 'an integer is required, not str'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %x requires an integer, not str'): eval("'%x' % (x,)", {'x': '1234'}) - with self.assertRaisesRegex(TypeError, 'must be real number, not str'): + with self.assertRaisesRegex(TypeError, + 'format argument 1: %f requires a real number, not str'): eval("'%f' % (x,)", {'x': '1234'}) with self.assertRaisesRegex(TypeError, 'not enough arguments for format string'): diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py index 2584fbf72d3..0a8dddb026f 100644 --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -1578,17 +1578,40 @@ def __int__(self): self.assertEqual('%X' % letter_m, '6D') self.assertEqual('%o' % letter_m, '155') self.assertEqual('%c' % letter_m, 'm') - self.assertRaisesRegex(TypeError, '%x format: an integer is required, not float', operator.mod, '%x', 3.14) - self.assertRaisesRegex(TypeError, '%X format: an integer is required, not float', operator.mod, '%X', 2.11) - self.assertRaisesRegex(TypeError, '%o format: an integer is required, not float', operator.mod, '%o', 1.79) - self.assertRaisesRegex(TypeError, '%x format: an integer is required, not PseudoFloat', operator.mod, '%x', pi) - self.assertRaisesRegex(TypeError, '%x format: an integer is required, not complex', operator.mod, '%x', 3j) - self.assertRaisesRegex(TypeError, '%X format: an integer is required, not complex', operator.mod, '%X', 2j) - self.assertRaisesRegex(TypeError, '%o format: an integer is required, not complex', operator.mod, '%o', 1j) - self.assertRaisesRegex(TypeError, '%u format: a real number is required, not complex', operator.mod, '%u', 3j) - self.assertRaisesRegex(TypeError, '%i format: a real number is required, not complex', operator.mod, '%i', 2j) - self.assertRaisesRegex(TypeError, '%d format: a real number is required, not complex', operator.mod, '%d', 1j) - self.assertRaisesRegex(TypeError, r'%c requires an int or a unicode character, not .*\.PseudoFloat', operator.mod, '%c', pi) + with self.assertRaisesRegex(TypeError, + 'format argument: %x requires an integer, not float'): + '%x' % 3.14 + with self.assertRaisesRegex(TypeError, + 'format argument: %X requires an integer, not float'): + '%X' % 2.11 + with self.assertRaisesRegex(TypeError, + 'format argument: %o requires an integer, not float'): + '%o' % 1.79 + with self.assertRaisesRegex(TypeError, + r'format argument: %x requires an integer, not .*\.PseudoFloat'): + '%x' % pi + with self.assertRaisesRegex(TypeError, + 'format argument: %x requires an integer, not complex'): + '%x' % 3j + with self.assertRaisesRegex(TypeError, + 'format argument: %X requires an integer, not complex'): + '%X' % 2j + with self.assertRaisesRegex(TypeError, + 'format argument: %o requires an integer, not complex'): + '%o' % 1j + with self.assertRaisesRegex(TypeError, + 'format argument: %u requires a real number, not complex'): + '%u' % 3j + with self.assertRaisesRegex(TypeError, + 'format argument: %i requires a real number, not complex'): + '%i' % 2j + with self.assertRaisesRegex(TypeError, + 'format argument: %d requires a real number, not complex'): + '%d' % 1j + with self.assertRaisesRegex(TypeError, + r'format argument: %c requires an integer or a unicode character, ' + r'not .*\.PseudoFloat'): + '%c' % pi class RaisingNumber: def __int__(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-10-06-06.gh-issue-142037.OpIGzK.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-10-06-06.gh-issue-142037.OpIGzK.rst new file mode 100644 index 00000000000..6a59be7726f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-29-10-06-06.gh-issue-142037.OpIGzK.rst @@ -0,0 +1,7 @@ +Improve error messages for printf-style formatting. +For errors in the format string, always include the position of the +start of the format unit. +For errors related to the formatted arguments, always include the number +or the name of the argument. +Raise more specific errors and include more information (type and number +of arguments, most probable causes of error). diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 56de99bde11..b85cbfe43e1 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -404,26 +404,44 @@ PyBytes_FromFormat(const char *format, ...) /* Helpers for formatstring */ +#define FORMAT_ERROR(EXC, FMT, ...) do { \ + if (key != NULL) { \ + PyErr_Format((EXC), "format argument %R: " FMT, \ + key, __VA_ARGS__); \ + } \ + else if (argidx >= 0) { \ + PyErr_Format((EXC), "format argument %zd: " FMT, \ + argidx, __VA_ARGS__); \ + } \ + else { \ + PyErr_Format((EXC), "format argument: " FMT, __VA_ARGS__); \ + } \ +} while (0) + Py_LOCAL_INLINE(PyObject *) -getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) +getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx, int allowone) { Py_ssize_t argidx = *p_argidx; if (argidx < arglen) { (*p_argidx)++; - if (arglen < 0) - return args; - else + if (arglen >= 0) { return PyTuple_GetItem(args, argidx); + } + else if (allowone) { + return args; + } } - PyErr_SetString(PyExc_TypeError, - "not enough arguments for format string"); + PyErr_Format(PyExc_TypeError, + "not enough arguments for format string (got %zd)", + arglen < 0 ? 1 : arglen); return NULL; } /* Returns a new reference to a PyBytes object, or NULL on failure. */ static char* -formatfloat(PyObject *v, int flags, int prec, int type, +formatfloat(PyObject *v, Py_ssize_t argidx, PyObject *key, + int flags, int prec, int type, PyObject **p_result, PyBytesWriter *writer, char *str) { char *p; @@ -434,8 +452,11 @@ formatfloat(PyObject *v, int flags, int prec, int type, x = PyFloat_AsDouble(v); if (x == -1.0 && PyErr_Occurred()) { - PyErr_Format(PyExc_TypeError, "float argument required, " - "not %.200s", Py_TYPE(v)->tp_name); + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + FORMAT_ERROR(PyExc_TypeError, + "%%%c requires a real number, not %T", + type, v); + } return NULL; } @@ -470,7 +491,8 @@ formatfloat(PyObject *v, int flags, int prec, int type, } static PyObject * -formatlong(PyObject *v, int flags, int prec, int type) +formatlong(PyObject *v, Py_ssize_t argidx, PyObject *key, + int flags, int prec, int type) { PyObject *result, *iobj; if (PyLong_Check(v)) @@ -490,20 +512,21 @@ formatlong(PyObject *v, int flags, int prec, int type) if (!PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; } - PyErr_Format(PyExc_TypeError, - "%%%c format: %s is required, not %.200s", type, - (type == 'o' || type == 'x' || type == 'X') ? "an integer" - : "a real number", - Py_TYPE(v)->tp_name); + FORMAT_ERROR(PyExc_TypeError, + "%%%c requires %s, not %T", + type, + (type == 'o' || type == 'x' || type == 'X') ? "an integer" + : "a real number", + v); return NULL; } static int -byte_converter(PyObject *arg, char *p) +byte_converter(PyObject *arg, Py_ssize_t argidx, PyObject *key, char *p) { if (PyBytes_Check(arg)) { if (PyBytes_GET_SIZE(arg) != 1) { - PyErr_Format(PyExc_TypeError, + FORMAT_ERROR(PyExc_TypeError, "%%c requires an integer in range(256) or " "a single byte, not a bytes object of length %zd", PyBytes_GET_SIZE(arg)); @@ -514,7 +537,7 @@ byte_converter(PyObject *arg, char *p) } else if (PyByteArray_Check(arg)) { if (PyByteArray_GET_SIZE(arg) != 1) { - PyErr_Format(PyExc_TypeError, + FORMAT_ERROR(PyExc_TypeError, "%%c requires an integer in range(256) or " "a single byte, not a bytearray object of length %zd", PyByteArray_GET_SIZE(arg)); @@ -531,23 +554,25 @@ byte_converter(PyObject *arg, char *p) } if (!(0 <= ival && ival <= 255)) { /* this includes an overflow in converting to C long */ - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(256)"); + FORMAT_ERROR(PyExc_OverflowError, + "%%c argument not in range(256)%s", ""); return 0; } *p = (char)ival; return 1; } - PyErr_Format(PyExc_TypeError, - "%%c requires an integer in range(256) or a single byte, not %T", - arg); + FORMAT_ERROR(PyExc_TypeError, + "%%c requires an integer in range(256) or " + "a single byte, not %T", + arg); return 0; } static PyObject *_PyBytes_FromBuffer(PyObject *x); static PyObject * -format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) +format_obj(PyObject *v, Py_ssize_t argidx, PyObject *key, + const char **pbuf, Py_ssize_t *plen) { PyObject *func, *result; /* is it a bytes object? */ @@ -589,10 +614,10 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) *plen = PyBytes_GET_SIZE(result); return result; } - PyErr_Format(PyExc_TypeError, + FORMAT_ERROR(PyExc_TypeError, "%%b requires a bytes-like object, " - "or an object that implements __bytes__, not '%.100s'", - Py_TYPE(v)->tp_name); + "or an object that implements __bytes__, not %T", + v); return NULL; } @@ -607,6 +632,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, Py_ssize_t fmtcnt; int args_owned = 0; PyObject *dict = NULL; + PyObject *key = NULL; if (args == NULL) { PyErr_BadInternalCall(); @@ -680,15 +706,17 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, fmtcnt--; continue; } + Py_CLEAR(key); + const char *fmtstart = fmt; if (*fmt == '(') { const char *keystart; Py_ssize_t keylen; - PyObject *key; int pcount = 1; if (dict == NULL) { - PyErr_SetString(PyExc_TypeError, - "format requires a mapping"); + PyErr_Format(PyExc_TypeError, + "format requires a mapping, not %T", + args); goto error; } ++fmt; @@ -704,8 +732,10 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, } keylen = fmt - keystart - 1; if (fmtcnt < 0 || pcount > 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format key"); + PyErr_Format(PyExc_ValueError, + "stray %% or incomplete format key " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); goto error; } key = PyBytes_FromStringAndSize(keystart, @@ -717,13 +747,21 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, args_owned = 0; } args = PyObject_GetItem(dict, key); - Py_DECREF(key); if (args == NULL) { goto error; } args_owned = 1; - arglen = -1; - argidx = -2; + arglen = -3; + argidx = -4; + } + else { + if (arglen < -1) { + PyErr_Format(PyExc_ValueError, + "format requires a parenthesised mapping key " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); + goto error; + } } /* Parse flags. Example: "%+i" => flags=F_SIGN. */ @@ -740,17 +778,28 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, /* Parse width. Example: "%10s" => width=10 */ if (c == '*') { - v = getnextarg(args, arglen, &argidx); + if (arglen < -1) { + PyErr_Format(PyExc_ValueError, + "* cannot be used with a parenthesised mapping key " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); + goto error; + } + v = getnextarg(args, arglen, &argidx, 0); if (v == NULL) goto error; if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); + FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v); goto error; } width = PyLong_AsSsize_t(v); - if (width == -1 && PyErr_Occurred()) + if (width == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + FORMAT_ERROR(PyExc_OverflowError, + "too big for width%s", ""); + } goto error; + } if (width < 0) { flags |= F_LJUST; width = -width; @@ -765,9 +814,9 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, if (!Py_ISDIGIT(c)) break; if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) { - PyErr_SetString( - PyExc_ValueError, - "width too big"); + PyErr_Format(PyExc_ValueError, + "width too big at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); goto error; } width = width*10 + (c - '0'); @@ -780,18 +829,29 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, if (--fmtcnt >= 0) c = *fmt++; if (c == '*') { - v = getnextarg(args, arglen, &argidx); + if (arglen < -1) { + PyErr_Format(PyExc_ValueError, + "* cannot be used with a parenthesised mapping key " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); + goto error; + } + v = getnextarg(args, arglen, &argidx, 0); if (v == NULL) goto error; if (!PyLong_Check(v)) { - PyErr_SetString( - PyExc_TypeError, - "* wants int"); + FORMAT_ERROR(PyExc_TypeError, + "* requires int, not %T", v); goto error; } prec = PyLong_AsInt(v); - if (prec == -1 && PyErr_Occurred()) + if (prec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + FORMAT_ERROR(PyExc_OverflowError, + "too big for precision%s", ""); + } goto error; + } if (prec < 0) prec = 0; if (--fmtcnt >= 0) @@ -804,9 +864,9 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, if (!Py_ISDIGIT(c)) break; if (prec > (INT_MAX - ((int)c - '0')) / 10) { - PyErr_SetString( - PyExc_ValueError, - "prec too big"); + PyErr_Format(PyExc_ValueError, + "precision too big at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); goto error; } prec = prec*10 + (c - '0'); @@ -820,11 +880,12 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, } } if (fmtcnt < 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format"); + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd", + (Py_ssize_t)(fmtstart - format - 1)); goto error; } - v = getnextarg(args, arglen, &argidx); + v = getnextarg(args, arglen, &argidx, 1); if (v == NULL) goto error; @@ -852,7 +913,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, case 's': // %s is only for 2/3 code; 3 only code should use %b case 'b': - temp = format_obj(v, &pbuf, &len); + temp = format_obj(v, argidx, key, &pbuf, &len); if (temp == NULL) goto error; if (prec >= 0 && len > prec) @@ -900,7 +961,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, continue; } - temp = formatlong(v, flags, prec, c); + temp = formatlong(v, argidx, key, flags, prec, c); if (!temp) goto error; assert(PyUnicode_IS_ASCII(temp)); @@ -921,13 +982,13 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, && !(flags & (F_SIGN | F_BLANK))) { /* Fast path */ - res = formatfloat(v, flags, prec, c, NULL, writer, res); + res = formatfloat(v, argidx, key, flags, prec, c, NULL, writer, res); if (res == NULL) goto error; continue; } - if (!formatfloat(v, flags, prec, c, &temp, NULL, res)) + if (!formatfloat(v, argidx, key, flags, prec, c, &temp, NULL, res)) goto error; pbuf = PyBytes_AS_STRING(temp); len = PyBytes_GET_SIZE(temp); @@ -938,7 +999,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, case 'c': pbuf = &onechar; - len = byte_converter(v, &onechar); + len = byte_converter(v, argidx, key, &onechar); if (!len) goto error; if (width == -1) { @@ -949,11 +1010,36 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, break; default: - PyErr_Format(PyExc_ValueError, - "unsupported format character '%c' (0x%x) " - "at index %zd", - c, c, - (Py_ssize_t)(fmt - 1 - format)); + if (Py_ISALPHA(c)) { + PyErr_Format(PyExc_ValueError, + "unsupported format %%%c at position %zd", + c, (Py_ssize_t)(fmtstart - format - 1)); + } + else if (c == '\'') { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character \"'\" " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1), + (Py_ssize_t)(fmt - format - 1)); + } + else if (c >= 32 && c < 127 && c != '\'') { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character '%c' " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1), + c, (Py_ssize_t)(fmt - format - 1)); + } + else { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character with code 0x%02x " + "at position %zd", + (Py_ssize_t)(fmtstart - format - 1), + Py_CHARMASK(c), + (Py_ssize_t)(fmt - format - 1)); + } goto error; } @@ -1042,6 +1128,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, } if (dict && (argidx < arglen)) { + // XXX: Never happens? PyErr_SetString(PyExc_TypeError, "not all arguments converted during bytes formatting"); Py_XDECREF(temp); @@ -1061,8 +1148,11 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, } /* until end */ if (argidx < arglen && !dict) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during bytes formatting"); + PyErr_Format(PyExc_TypeError, + "not all arguments converted during bytes formatting " + "(required %zd, got %zd)", + arglen < 0 ? 0 : argidx, + arglen < 0 ? 1 : arglen); goto error; } @@ -1072,6 +1162,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, return PyBytesWriter_FinishWithPointer(writer, res); error: + Py_XDECREF(key); PyBytesWriter_Discard(writer); if (args_owned) { Py_DECREF(args); diff --git a/Objects/unicode_format.c b/Objects/unicode_format.c index 26bdae55d8b..e2790c8c1d4 100644 --- a/Objects/unicode_format.c +++ b/Objects/unicode_format.c @@ -72,23 +72,44 @@ struct unicode_format_arg_t { Py_ssize_t width; int prec; int sign; + Py_ssize_t fmtstart; + PyObject *key; }; +// Use FORMAT_ERROR("...%s", "") when there is no arguments. +#define FORMAT_ERROR(EXC, FMT, ...) do { \ + if (arg->key != NULL) { \ + PyErr_Format((EXC), "format argument %R: " FMT, \ + arg->key, __VA_ARGS__); \ + } \ + else if (ctx->argidx >= 0) { \ + PyErr_Format((EXC), "format argument %zd: " FMT, \ + ctx->argidx, __VA_ARGS__); \ + } \ + else { \ + PyErr_Format((EXC), "format argument: " FMT, __VA_ARGS__); \ + } \ +} while (0) + + static PyObject * -unicode_format_getnextarg(struct unicode_formatter_t *ctx) +unicode_format_getnextarg(struct unicode_formatter_t *ctx, int allowone) { Py_ssize_t argidx = ctx->argidx; - if (argidx < ctx->arglen) { + if (argidx < ctx->arglen && (allowone || ctx->arglen >= 0)) { ctx->argidx++; - if (ctx->arglen < 0) - return ctx->args; - else + if (ctx->arglen >= 0) { return PyTuple_GetItem(ctx->args, argidx); + } + else if (allowone) { + return ctx->args; + } } - PyErr_SetString(PyExc_TypeError, - "not enough arguments for format string"); + PyErr_Format(PyExc_TypeError, + "not enough arguments for format string (got %zd)", + ctx->arglen < 0 ? 1 : ctx->arglen); return NULL; } @@ -100,7 +121,9 @@ unicode_format_getnextarg(struct unicode_formatter_t *ctx) Return 0 on success, raise an exception and return -1 on error. */ static int -formatfloat(PyObject *v, struct unicode_format_arg_t *arg, +formatfloat(PyObject *v, + struct unicode_formatter_t *ctx, + struct unicode_format_arg_t *arg, PyObject **p_output, _PyUnicodeWriter *writer) { @@ -111,8 +134,14 @@ formatfloat(PyObject *v, struct unicode_format_arg_t *arg, int dtoa_flags = 0; x = PyFloat_AsDouble(v); - if (x == -1.0 && PyErr_Occurred()) + if (x == -1.0 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + FORMAT_ERROR(PyExc_TypeError, + "%%%c requires a real number, not %T", + arg->ch, v); + } return -1; + } prec = arg->prec; if (prec < 0) @@ -287,6 +316,7 @@ _PyUnicode_FormatLong(PyObject *val, int alt, int prec, int type) * -1 and raise an exception on error */ static int mainformatlong(PyObject *v, + struct unicode_formatter_t *ctx, struct unicode_format_arg_t *arg, PyObject **p_output, _PyUnicodeWriter *writer) @@ -364,16 +394,14 @@ mainformatlong(PyObject *v, case 'o': case 'x': case 'X': - PyErr_Format(PyExc_TypeError, - "%%%c format: an integer is required, " - "not %.200s", - type, Py_TYPE(v)->tp_name); + FORMAT_ERROR(PyExc_TypeError, + "%%%c requires an integer, not %T", + arg->ch, v); break; default: - PyErr_Format(PyExc_TypeError, - "%%%c format: a real number is required, " - "not %.200s", - type, Py_TYPE(v)->tp_name); + FORMAT_ERROR(PyExc_TypeError, + "%%%c requires a real number, not %T", + arg->ch, v); break; } return -1; @@ -381,15 +409,17 @@ mainformatlong(PyObject *v, static Py_UCS4 -formatchar(PyObject *v) +formatchar(PyObject *v, + struct unicode_formatter_t *ctx, + struct unicode_format_arg_t *arg) { /* presume that the buffer is at least 3 characters long */ if (PyUnicode_Check(v)) { if (PyUnicode_GET_LENGTH(v) == 1) { return PyUnicode_READ_CHAR(v, 0); } - PyErr_Format(PyExc_TypeError, - "%%c requires an int or a unicode character, " + FORMAT_ERROR(PyExc_TypeError, + "%%c requires an integer or a unicode character, " "not a string of length %zd", PyUnicode_GET_LENGTH(v)); return (Py_UCS4) -1; @@ -399,18 +429,18 @@ formatchar(PyObject *v) long x = PyLong_AsLongAndOverflow(v, &overflow); if (x == -1 && PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "%%c requires an int or a unicode character, not %T", + FORMAT_ERROR(PyExc_TypeError, + "%%c requires an integer or a unicode character, " + "not %T", v); - return (Py_UCS4) -1; } return (Py_UCS4) -1; } if (x < 0 || x > MAX_UNICODE) { /* this includes an overflow in converting to C long */ - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x110000)"); + FORMAT_ERROR(PyExc_OverflowError, + "%%c argument not in range(0x110000)%s", ""); return (Py_UCS4) -1; } @@ -438,12 +468,12 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, /* Get argument value from a dictionary. Example: "%(name)s". */ Py_ssize_t keystart; Py_ssize_t keylen; - PyObject *key; int pcount = 1; if (ctx->dict == NULL) { - PyErr_SetString(PyExc_TypeError, - "format requires a mapping"); + PyErr_Format(PyExc_TypeError, + "format requires a mapping, not %T", + ctx->args); return -1; } ++ctx->fmtpos; @@ -460,25 +490,34 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, } keylen = ctx->fmtpos - keystart - 1; if (ctx->fmtcnt < 0 || pcount > 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format key"); + PyErr_Format(PyExc_ValueError, + "stray %% or incomplete format key at position %zd", + arg->fmtstart); return -1; } - key = PyUnicode_Substring(ctx->fmtstr, - keystart, keystart + keylen); - if (key == NULL) + arg->key = PyUnicode_Substring(ctx->fmtstr, + keystart, keystart + keylen); + if (arg->key == NULL) return -1; if (ctx->args_owned) { ctx->args_owned = 0; Py_DECREF(ctx->args); } - ctx->args = PyObject_GetItem(ctx->dict, key); - Py_DECREF(key); + ctx->args = PyObject_GetItem(ctx->dict, arg->key); if (ctx->args == NULL) return -1; ctx->args_owned = 1; - ctx->arglen = -1; - ctx->argidx = -2; + ctx->arglen = -3; + ctx->argidx = -4; + } + else { + if (ctx->arglen < -1) { + PyErr_Format(PyExc_ValueError, + "format requires a parenthesised mapping key " + "at position %zd", + arg->fmtstart); + return -1; + } } /* Parse flags. Example: "%+i" => flags=F_SIGN. */ @@ -497,17 +536,28 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, /* Parse width. Example: "%10s" => width=10 */ if (arg->ch == '*') { - v = unicode_format_getnextarg(ctx); + if (ctx->arglen < -1) { + PyErr_Format(PyExc_ValueError, + "* cannot be used with a parenthesised mapping key " + "at position %zd", + arg->fmtstart); + return -1; + } + v = unicode_format_getnextarg(ctx, 0); if (v == NULL) return -1; if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); + FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v); return -1; } arg->width = PyLong_AsSsize_t(v); - if (arg->width == -1 && PyErr_Occurred()) + if (arg->width == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + FORMAT_ERROR(PyExc_OverflowError, + "too big for width%s", ""); + } return -1; + } if (arg->width < 0) { arg->flags |= F_LJUST; arg->width = -arg->width; @@ -528,8 +578,9 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, mixing signed and unsigned comparison. Since arg->ch is between '0' and '9', casting to int is safe. */ if (arg->width > (PY_SSIZE_T_MAX - ((int)arg->ch - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "width too big"); + PyErr_Format(PyExc_ValueError, + "width too big at position %zd", + arg->fmtstart); return -1; } arg->width = arg->width*10 + (arg->ch - '0'); @@ -544,17 +595,28 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, ctx->fmtpos++; } if (arg->ch == '*') { - v = unicode_format_getnextarg(ctx); + if (ctx->arglen < -1) { + PyErr_Format(PyExc_ValueError, + "* cannot be used with a parenthesised mapping key " + "at position %zd", + arg->fmtstart); + return -1; + } + v = unicode_format_getnextarg(ctx, 0); if (v == NULL) return -1; if (!PyLong_Check(v)) { - PyErr_SetString(PyExc_TypeError, - "* wants int"); + FORMAT_ERROR(PyExc_TypeError, "* requires int, not %T", v); return -1; } arg->prec = PyLong_AsInt(v); - if (arg->prec == -1 && PyErr_Occurred()) + if (arg->prec == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + FORMAT_ERROR(PyExc_OverflowError, + "too big for precision%s", ""); + } return -1; + } if (arg->prec < 0) arg->prec = 0; if (--ctx->fmtcnt >= 0) { @@ -570,8 +632,9 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, if (arg->ch < '0' || arg->ch > '9') break; if (arg->prec > (INT_MAX - ((int)arg->ch - '0')) / 10) { - PyErr_SetString(PyExc_ValueError, - "precision too big"); + PyErr_Format(PyExc_ValueError, + "precision too big at position %zd", + arg->fmtstart); return -1; } arg->prec = arg->prec*10 + (arg->ch - '0'); @@ -589,8 +652,8 @@ unicode_format_arg_parse(struct unicode_formatter_t *ctx, } } if (ctx->fmtcnt < 0) { - PyErr_SetString(PyExc_ValueError, - "incomplete format"); + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd", arg->fmtstart); return -1; } return 0; @@ -624,7 +687,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx, if (ctx->fmtcnt == 0) ctx->writer.overallocate = 0; - v = unicode_format_getnextarg(ctx); + v = unicode_format_getnextarg(ctx, 1); if (v == NULL) return -1; @@ -660,7 +723,7 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx, case 'x': case 'X': { - int ret = mainformatlong(v, arg, p_str, writer); + int ret = mainformatlong(v, ctx, arg, p_str, writer); if (ret != 0) return ret; arg->sign = 1; @@ -677,19 +740,19 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx, && !(arg->flags & (F_SIGN | F_BLANK))) { /* Fast path */ - if (formatfloat(v, arg, NULL, writer) == -1) + if (formatfloat(v, ctx, arg, NULL, writer) == -1) return -1; return 1; } arg->sign = 1; - if (formatfloat(v, arg, p_str, NULL) == -1) + if (formatfloat(v, ctx, arg, p_str, NULL) == -1) return -1; break; case 'c': { - Py_UCS4 ch = formatchar(v); + Py_UCS4 ch = formatchar(v, ctx, arg); if (ch == (Py_UCS4) -1) return -1; if (arg->width == -1 && arg->prec == -1) { @@ -703,12 +766,38 @@ unicode_format_arg_format(struct unicode_formatter_t *ctx, } default: - PyErr_Format(PyExc_ValueError, - "unsupported format character '%c' (0x%x) " - "at index %zd", - (31<=arg->ch && arg->ch<=126) ? (char)arg->ch : '?', - (int)arg->ch, - ctx->fmtpos - 1); + if (arg->ch < 128 && Py_ISALPHA(arg->ch)) { + PyErr_Format(PyExc_ValueError, + "unsupported format %%%c at position %zd", + (int)arg->ch, arg->fmtstart); + } + else if (arg->ch == '\'') { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character \"'\" at position %zd", + arg->fmtstart, + ctx->fmtpos - 1); + } + else if (arg->ch >= 32 && arg->ch < 127) { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character '%c' at position %zd", + arg->fmtstart, + (int)arg->ch, ctx->fmtpos - 1); + } + else if (Py_UNICODE_ISPRINTABLE(arg->ch)) { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character '%c' (U+%04X) at position %zd", + arg->fmtstart, + (int)arg->ch, (int)arg->ch, ctx->fmtpos - 1); + } + else { + PyErr_Format(PyExc_ValueError, + "stray %% at position %zd or unexpected " + "format character U+%04X at position %zd", + arg->fmtstart, (int)arg->ch, ctx->fmtpos - 1); + } return -1; } if (*p_str == NULL) @@ -892,29 +981,40 @@ unicode_format_arg(struct unicode_formatter_t *ctx) arg.width = -1; arg.prec = -1; arg.sign = 0; + arg.fmtstart = ctx->fmtpos - 1; + arg.key = NULL; str = NULL; ret = unicode_format_arg_parse(ctx, &arg); - if (ret == -1) - return -1; + if (ret == -1) { + goto onError; + } ret = unicode_format_arg_format(ctx, &arg, &str); - if (ret == -1) - return -1; + if (ret == -1) { + goto onError; + } if (ret != 1) { ret = unicode_format_arg_output(ctx, &arg, str); Py_DECREF(str); - if (ret == -1) - return -1; + if (ret == -1) { + goto onError; + } } if (ctx->dict && (ctx->argidx < ctx->arglen)) { + // XXX: Never happens? PyErr_SetString(PyExc_TypeError, "not all arguments converted during string formatting"); - return -1; + goto onError; } + Py_XDECREF(arg.key); return 0; + + onError: + Py_XDECREF(arg.key); + return -1; } @@ -983,8 +1083,11 @@ PyUnicode_Format(PyObject *format, PyObject *args) } if (ctx.argidx < ctx.arglen && !ctx.dict) { - PyErr_SetString(PyExc_TypeError, - "not all arguments converted during string formatting"); + PyErr_Format(PyExc_TypeError, + "not all arguments converted during string formatting " + "(required %zd, got %zd)", + ctx.arglen < 0 ? 0 : ctx.argidx, + ctx.arglen < 0 ? 1 : ctx.arglen); goto onError; } From 27246c34829ef87adaafafa10e3f946ade7d0de8 Mon Sep 17 00:00:00 2001 From: mdehoon Date: Sun, 25 Jan 2026 00:20:14 +0900 Subject: [PATCH 070/133] Remove stray typedef in _tkinter.c (GH-142924) Co-authored-by: Michiel de Hoon --- Modules/_tkinter.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index e6c0c1ff46c..1524d02d9e5 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -235,7 +235,6 @@ static PyThread_type_lock tcl_lock = 0; #ifdef TCL_THREADS static Tcl_ThreadDataKey state_key; -typedef PyThreadState *ThreadSpecificData; #define tcl_tstate \ (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*))) #else From 979d92fefc0b6863c9783659f80d36cdfac90506 Mon Sep 17 00:00:00 2001 From: Yi Yang <1948638989@qq.com> Date: Sun, 25 Jan 2026 00:09:29 +0800 Subject: [PATCH 071/133] gh-144140: Optimize len for string constants in optimizer (GH-144142) --- Lib/test/test_capi/test_opt.py | 15 +++++++++++++++ Python/optimizer_bytecodes.c | 23 ++++++++++++++++++----- Python/optimizer_cases.c.h | 25 ++++++++++++++++++++----- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index ff3adb1d454..0a02f29d978 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2419,6 +2419,21 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertIn("_POP_TOP_NOP", uops) + def test_call_len_string(self): + def testfunc(n): + for _ in range(n): + _ = len("abc") + d = '' + _ = len(d) + _ = len(b"def") + _ = len(b"") + + _, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_CALL_LEN", uops) + self.assertEqual(count_ops(ex, "_SHUFFLE_3_LOAD_CONST_INLINE_BORROW"), 4) + def test_call_len_known_length_small_int(self): # Make sure that len(t) is optimized for a tuple of length 5. # See https://github.com/python/cpython/issues/139393. diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 38cd088d9fb..9bc6075adc7 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1455,15 +1455,28 @@ dummy_func(void) { op(_CALL_LEN, (callable, null, arg -- res, a, c)) { res = sym_new_type(ctx, &PyLong_Type); - Py_ssize_t tuple_length = sym_tuple_length(arg); - if (tuple_length >= 0) { - PyObject *temp = PyLong_FromSsize_t(tuple_length); + Py_ssize_t length = sym_tuple_length(arg); + + // Not a tuple, check if it's a const string + if (length < 0 && sym_is_const(ctx, arg)) { + PyObject *const_val = sym_get_const(ctx, arg); + if (const_val != NULL) { + if (PyUnicode_CheckExact(const_val)) { + length = PyUnicode_GET_LENGTH(const_val); + } + else if (PyBytes_CheckExact(const_val)) { + length = PyBytes_GET_SIZE(const_val); + } + } + } + + if (length >= 0) { + PyObject *temp = PyLong_FromSsize_t(length); if (temp == NULL) { goto error; } if (_Py_IsImmortal(temp)) { - ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, - 0, (uintptr_t)temp); + ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); } res = sym_new_const(ctx, temp); Py_DECREF(temp); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index e9405473fe2..2cd1f833dc3 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3309,15 +3309,30 @@ arg = stack_pointer[-1]; callable = stack_pointer[-3]; res = sym_new_type(ctx, &PyLong_Type); - Py_ssize_t tuple_length = sym_tuple_length(arg); - if (tuple_length >= 0) { - PyObject *temp = PyLong_FromSsize_t(tuple_length); + Py_ssize_t length = sym_tuple_length(arg); + if (length < 0 && sym_is_const(ctx, arg)) { + PyObject *const_val = sym_get_const(ctx, arg); + if (const_val != NULL) { + if (PyUnicode_CheckExact(const_val)) { + length = PyUnicode_GET_LENGTH(const_val); + } + else if (PyBytes_CheckExact(const_val)) { + CHECK_STACK_BOUNDS(-2); + stack_pointer[-3] = res; + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + length = PyBytes_GET_SIZE(const_val); + stack_pointer += 2; + } + } + } + if (length >= 0) { + PyObject *temp = PyLong_FromSsize_t(length); if (temp == NULL) { goto error; } if (_Py_IsImmortal(temp)) { - ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, - 0, (uintptr_t)temp); + ADD_OP(_SHUFFLE_3_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)temp); } res = sym_new_const(ctx, temp); CHECK_STACK_BOUNDS(-2); From a51bf70f95ccab420fb6afec009e8192065f2beb Mon Sep 17 00:00:00 2001 From: Yashraj Date: Sun, 25 Jan 2026 20:51:27 +0530 Subject: [PATCH 072/133] gh-143504: Expose CELL status of a symbol in symtable (#143549) --- Doc/library/symtable.rst | 12 ++++++++++++ Doc/whatsnew/3.15.rst | 7 +++++++ Lib/symtable.py | 13 +++++++++++++ Lib/test/test_symtable.py | 4 ++++ .../2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst | 1 + 5 files changed, 37 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst index f5e6f9f8acf..0b722d7d4e3 100644 --- a/Doc/library/symtable.rst +++ b/Doc/library/symtable.rst @@ -180,6 +180,12 @@ Examining Symbol Tables Return a tuple containing names of :term:`free (closure) variables ` in this function. + .. method:: get_cells() + + Return a tuple containing names of :term:`cell variables ` in this table. + + .. versionadded:: next + .. class:: Class @@ -291,6 +297,12 @@ Examining Symbol Tables Return ``True`` if the symbol is referenced in its block, but not assigned to. + .. method:: is_cell() + + Return ``True`` if the symbol is referenced but not assigned in a nested block. + + .. versionadded:: next + .. method:: is_free_class() Return *True* if a class-scoped symbol is free from diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 8c92ac8e031..8c3223d9a78 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -737,6 +737,13 @@ ssl (Contributed by Ron Frederick in :gh:`138252`.) +symtable +-------- + +* Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell` methods. + (Contributed by Yashp002 in :gh:`143504`.) + + sys --- diff --git a/Lib/symtable.py b/Lib/symtable.py index 4c832e68f94..45610fd5612 100644 --- a/Lib/symtable.py +++ b/Lib/symtable.py @@ -184,6 +184,7 @@ class Function(SymbolTable): __frees = None __globals = None __nonlocals = None + __cells = None def __idents_matching(self, test_func): return tuple(ident for ident in self.get_identifiers() @@ -229,6 +230,14 @@ def get_frees(self): self.__frees = self.__idents_matching(is_free) return self.__frees + def get_cells(self): + """Return a tuple of cell variables in the function. + """ + if self.__cells is None: + is_cell = lambda x: _get_scope(x) == CELL + self.__cells = self.__idents_matching(is_cell) + return self.__cells + class Class(SymbolTable): @@ -342,6 +351,10 @@ def is_free(self): """ return bool(self.__scope == FREE) + def is_cell(self): + """Return *True* if the symbol is a cell variable.""" + return bool(self.__scope == CELL) + def is_free_class(self): """Return *True* if a class-scoped symbol is free from the perspective of a method.""" diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py index 094ab8f573e..c748243110d 100644 --- a/Lib/test/test_symtable.py +++ b/Lib/test/test_symtable.py @@ -255,6 +255,7 @@ def test_function_info(self): self.assertEqual(sorted(func.get_locals()), expected) self.assertEqual(sorted(func.get_globals()), ["bar", "glob", "some_assigned_global_var"]) self.assertEqual(self.internal.get_frees(), ("x",)) + self.assertEqual(self.spam.get_cells(), ("some_var", "x",)) def test_globals(self): self.assertTrue(self.spam.lookup("glob").is_global()) @@ -284,6 +285,9 @@ def test_local(self): def test_free(self): self.assertTrue(self.internal.lookup("x").is_free()) + def test_cells(self): + self.assertTrue(self.spam.lookup("x").is_cell()) + def test_referenced(self): self.assertTrue(self.internal.lookup("x").is_referenced()) self.assertTrue(self.spam.lookup("internal").is_referenced()) diff --git a/Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst b/Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst new file mode 100644 index 00000000000..e0c2c287f57 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-24-13-49-05.gh-issue-143594.nilGlg.rst @@ -0,0 +1 @@ +Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell` methods. From 6e55337f8aca650328e7f07decf2e8171e685532 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 26 Jan 2026 03:24:44 +0900 Subject: [PATCH 073/133] gh-143995: Eliminate redundant refcounting in the JIT from LOAD_ATTR_MODULE (GH-143996) --- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_ids.h | 1976 +++++++++++---------- Include/internal/pycore_uop_metadata.h | 27 +- Lib/test/test_capi/test_opt.py | 17 + Modules/_testinternalcapi/test_cases.c.h | 9 +- Python/bytecodes.c | 12 +- Python/executor_cases.c.h | 73 +- Python/generated_cases.c.h | 9 +- Python/optimizer_analysis.c | 27 +- Python/optimizer_bytecodes.c | 9 +- Python/optimizer_cases.c.h | 25 +- 11 files changed, 1163 insertions(+), 1023 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 95dee5d3526..fe94dc6a24f 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1447,7 +1447,7 @@ _PyOpcode_macro_expansion[256] = { [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, - [LOAD_ATTR_MODULE] = { .nuops = 3, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_MODULE] = { .nuops = 4, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 8aa42933ec8..8712d1afc75 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -194,9 +194,10 @@ extern "C" { #define _INIT_CALL_PY_EXACT_ARGS_2 447 #define _INIT_CALL_PY_EXACT_ARGS_3 448 #define _INIT_CALL_PY_EXACT_ARGS_4 449 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW 450 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW 451 -#define _INSERT_NULL 452 +#define _INSERT_1_LOAD_CONST_INLINE 450 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW 451 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW 452 +#define _INSERT_NULL 453 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -206,1035 +207,1038 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 453 -#define _IS_OP 454 -#define _ITER_CHECK_LIST 455 -#define _ITER_CHECK_RANGE 456 -#define _ITER_CHECK_TUPLE 457 -#define _ITER_JUMP_LIST 458 -#define _ITER_JUMP_RANGE 459 -#define _ITER_JUMP_TUPLE 460 -#define _ITER_NEXT_LIST 461 -#define _ITER_NEXT_LIST_TIER_TWO 462 -#define _ITER_NEXT_RANGE 463 -#define _ITER_NEXT_TUPLE 464 +#define _IS_NONE 454 +#define _IS_OP 455 +#define _ITER_CHECK_LIST 456 +#define _ITER_CHECK_RANGE 457 +#define _ITER_CHECK_TUPLE 458 +#define _ITER_JUMP_LIST 459 +#define _ITER_JUMP_RANGE 460 +#define _ITER_JUMP_TUPLE 461 +#define _ITER_NEXT_LIST 462 +#define _ITER_NEXT_LIST_TIER_TWO 463 +#define _ITER_NEXT_RANGE 464 +#define _ITER_NEXT_TUPLE 465 #define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT -#define _JUMP_TO_TOP 465 +#define _JUMP_TO_TOP 466 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 466 -#define _LOAD_ATTR_CLASS 467 +#define _LOAD_ATTR 467 +#define _LOAD_ATTR_CLASS 468 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 468 -#define _LOAD_ATTR_METHOD_LAZY_DICT 469 -#define _LOAD_ATTR_METHOD_NO_DICT 470 -#define _LOAD_ATTR_METHOD_WITH_VALUES 471 -#define _LOAD_ATTR_MODULE 472 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 473 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 474 -#define _LOAD_ATTR_PROPERTY_FRAME 475 -#define _LOAD_ATTR_SLOT 476 -#define _LOAD_ATTR_WITH_HINT 477 +#define _LOAD_ATTR_INSTANCE_VALUE 469 +#define _LOAD_ATTR_METHOD_LAZY_DICT 470 +#define _LOAD_ATTR_METHOD_NO_DICT 471 +#define _LOAD_ATTR_METHOD_WITH_VALUES 472 +#define _LOAD_ATTR_MODULE 473 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 474 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 475 +#define _LOAD_ATTR_PROPERTY_FRAME 476 +#define _LOAD_ATTR_SLOT 477 +#define _LOAD_ATTR_WITH_HINT 478 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 478 +#define _LOAD_BYTECODE 479 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 479 -#define _LOAD_CONST_INLINE_BORROW 480 -#define _LOAD_CONST_UNDER_INLINE 481 -#define _LOAD_CONST_UNDER_INLINE_BORROW 482 +#define _LOAD_CONST_INLINE 480 +#define _LOAD_CONST_INLINE_BORROW 481 +#define _LOAD_CONST_UNDER_INLINE 482 +#define _LOAD_CONST_UNDER_INLINE_BORROW 483 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 483 -#define _LOAD_FAST_0 484 -#define _LOAD_FAST_1 485 -#define _LOAD_FAST_2 486 -#define _LOAD_FAST_3 487 -#define _LOAD_FAST_4 488 -#define _LOAD_FAST_5 489 -#define _LOAD_FAST_6 490 -#define _LOAD_FAST_7 491 +#define _LOAD_FAST 484 +#define _LOAD_FAST_0 485 +#define _LOAD_FAST_1 486 +#define _LOAD_FAST_2 487 +#define _LOAD_FAST_3 488 +#define _LOAD_FAST_4 489 +#define _LOAD_FAST_5 490 +#define _LOAD_FAST_6 491 +#define _LOAD_FAST_7 492 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 492 -#define _LOAD_FAST_BORROW_0 493 -#define _LOAD_FAST_BORROW_1 494 -#define _LOAD_FAST_BORROW_2 495 -#define _LOAD_FAST_BORROW_3 496 -#define _LOAD_FAST_BORROW_4 497 -#define _LOAD_FAST_BORROW_5 498 -#define _LOAD_FAST_BORROW_6 499 -#define _LOAD_FAST_BORROW_7 500 +#define _LOAD_FAST_BORROW 493 +#define _LOAD_FAST_BORROW_0 494 +#define _LOAD_FAST_BORROW_1 495 +#define _LOAD_FAST_BORROW_2 496 +#define _LOAD_FAST_BORROW_3 497 +#define _LOAD_FAST_BORROW_4 498 +#define _LOAD_FAST_BORROW_5 499 +#define _LOAD_FAST_BORROW_6 500 +#define _LOAD_FAST_BORROW_7 501 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 501 -#define _LOAD_GLOBAL_BUILTINS 502 -#define _LOAD_GLOBAL_MODULE 503 +#define _LOAD_GLOBAL 502 +#define _LOAD_GLOBAL_BUILTINS 503 +#define _LOAD_GLOBAL_MODULE 504 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 504 -#define _LOAD_SMALL_INT_0 505 -#define _LOAD_SMALL_INT_1 506 -#define _LOAD_SMALL_INT_2 507 -#define _LOAD_SMALL_INT_3 508 -#define _LOAD_SPECIAL 509 +#define _LOAD_SMALL_INT 505 +#define _LOAD_SMALL_INT_0 506 +#define _LOAD_SMALL_INT_1 507 +#define _LOAD_SMALL_INT_2 508 +#define _LOAD_SMALL_INT_3 509 +#define _LOAD_SPECIAL 510 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 510 +#define _MAKE_CALLARGS_A_TUPLE 511 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 511 +#define _MAKE_WARM 512 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 512 -#define _MAYBE_EXPAND_METHOD_KW 513 -#define _MONITOR_CALL 514 -#define _MONITOR_CALL_KW 515 -#define _MONITOR_JUMP_BACKWARD 516 -#define _MONITOR_RESUME 517 +#define _MAYBE_EXPAND_METHOD 513 +#define _MAYBE_EXPAND_METHOD_KW 514 +#define _MONITOR_CALL 515 +#define _MONITOR_CALL_KW 516 +#define _MONITOR_JUMP_BACKWARD 517 +#define _MONITOR_RESUME 518 #define _NOP NOP -#define _POP_CALL 518 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW 519 -#define _POP_CALL_ONE 520 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 521 -#define _POP_CALL_TWO 522 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 523 +#define _POP_CALL 519 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW 520 +#define _POP_CALL_ONE 521 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW 522 +#define _POP_CALL_TWO 523 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW 524 #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 524 -#define _POP_JUMP_IF_TRUE 525 +#define _POP_JUMP_IF_FALSE 525 +#define _POP_JUMP_IF_TRUE 526 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 526 -#define _POP_TOP_INT 527 -#define _POP_TOP_LOAD_CONST_INLINE 528 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 529 -#define _POP_TOP_NOP 530 -#define _POP_TOP_UNICODE 531 -#define _POP_TWO 532 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 533 +#define _POP_TOP_FLOAT 527 +#define _POP_TOP_INT 528 +#define _POP_TOP_LOAD_CONST_INLINE 529 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 530 +#define _POP_TOP_NOP 531 +#define _POP_TOP_UNICODE 532 +#define _POP_TWO 533 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 534 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 534 +#define _PUSH_FRAME 535 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 535 -#define _PY_FRAME_EX 536 -#define _PY_FRAME_GENERAL 537 -#define _PY_FRAME_KW 538 -#define _QUICKEN_RESUME 539 -#define _REPLACE_WITH_TRUE 540 +#define _PUSH_NULL_CONDITIONAL 536 +#define _PY_FRAME_EX 537 +#define _PY_FRAME_GENERAL 538 +#define _PY_FRAME_KW 539 +#define _QUICKEN_RESUME 540 +#define _REPLACE_WITH_TRUE 541 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 541 -#define _SEND 542 -#define _SEND_GEN_FRAME 543 +#define _SAVE_RETURN_OFFSET 542 +#define _SEND 543 +#define _SEND_GEN_FRAME 544 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 544 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 545 -#define _SPILL_OR_RELOAD 546 -#define _START_EXECUTOR 547 -#define _STORE_ATTR 548 -#define _STORE_ATTR_INSTANCE_VALUE 549 -#define _STORE_ATTR_SLOT 550 -#define _STORE_ATTR_WITH_HINT 551 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 545 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 546 +#define _SPILL_OR_RELOAD 547 +#define _START_EXECUTOR 548 +#define _STORE_ATTR 549 +#define _STORE_ATTR_INSTANCE_VALUE 550 +#define _STORE_ATTR_SLOT 551 +#define _STORE_ATTR_WITH_HINT 552 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 552 -#define _STORE_SUBSCR 553 -#define _STORE_SUBSCR_DICT 554 -#define _STORE_SUBSCR_LIST_INT 555 -#define _SWAP 556 -#define _SWAP_2 557 -#define _SWAP_3 558 -#define _SWAP_FAST 559 -#define _SWAP_FAST_0 560 -#define _SWAP_FAST_1 561 -#define _SWAP_FAST_2 562 -#define _SWAP_FAST_3 563 -#define _SWAP_FAST_4 564 -#define _SWAP_FAST_5 565 -#define _SWAP_FAST_6 566 -#define _SWAP_FAST_7 567 -#define _TIER2_RESUME_CHECK 568 -#define _TO_BOOL 569 +#define _STORE_SLICE 553 +#define _STORE_SUBSCR 554 +#define _STORE_SUBSCR_DICT 555 +#define _STORE_SUBSCR_LIST_INT 556 +#define _SWAP 557 +#define _SWAP_2 558 +#define _SWAP_3 559 +#define _SWAP_FAST 560 +#define _SWAP_FAST_0 561 +#define _SWAP_FAST_1 562 +#define _SWAP_FAST_2 563 +#define _SWAP_FAST_3 564 +#define _SWAP_FAST_4 565 +#define _SWAP_FAST_5 566 +#define _SWAP_FAST_6 567 +#define _SWAP_FAST_7 568 +#define _TIER2_RESUME_CHECK 569 +#define _TO_BOOL 570 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 570 -#define _TO_BOOL_LIST 571 +#define _TO_BOOL_INT 571 +#define _TO_BOOL_LIST 572 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 572 +#define _TO_BOOL_STR 573 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 573 -#define _UNARY_NEGATIVE 574 +#define _UNARY_INVERT 574 +#define _UNARY_NEGATIVE 575 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 575 -#define _UNPACK_SEQUENCE_LIST 576 -#define _UNPACK_SEQUENCE_TUPLE 577 -#define _UNPACK_SEQUENCE_TWO_TUPLE 578 +#define _UNPACK_SEQUENCE 576 +#define _UNPACK_SEQUENCE_LIST 577 +#define _UNPACK_SEQUENCE_TUPLE 578 +#define _UNPACK_SEQUENCE_TWO_TUPLE 579 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 578 -#define _BINARY_OP_r23 579 -#define _BINARY_OP_ADD_FLOAT_r03 580 -#define _BINARY_OP_ADD_FLOAT_r13 581 -#define _BINARY_OP_ADD_FLOAT_r23 582 -#define _BINARY_OP_ADD_INT_r03 583 -#define _BINARY_OP_ADD_INT_r13 584 -#define _BINARY_OP_ADD_INT_r23 585 -#define _BINARY_OP_ADD_UNICODE_r03 586 -#define _BINARY_OP_ADD_UNICODE_r13 587 -#define _BINARY_OP_ADD_UNICODE_r23 588 -#define _BINARY_OP_EXTEND_r23 589 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 590 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 591 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 592 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 593 -#define _BINARY_OP_MULTIPLY_INT_r03 594 -#define _BINARY_OP_MULTIPLY_INT_r13 595 -#define _BINARY_OP_MULTIPLY_INT_r23 596 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 597 -#define _BINARY_OP_SUBSCR_DICT_r23 598 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 599 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 600 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 601 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 602 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 603 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 604 -#define _BINARY_OP_SUBSCR_STR_INT_r23 605 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 606 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 607 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 608 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 609 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 610 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 611 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 612 -#define _BINARY_OP_SUBTRACT_INT_r03 613 -#define _BINARY_OP_SUBTRACT_INT_r13 614 -#define _BINARY_OP_SUBTRACT_INT_r23 615 -#define _BINARY_SLICE_r31 616 -#define _BUILD_INTERPOLATION_r01 617 -#define _BUILD_LIST_r01 618 -#define _BUILD_MAP_r01 619 -#define _BUILD_SET_r01 620 -#define _BUILD_SLICE_r01 621 -#define _BUILD_STRING_r01 622 -#define _BUILD_TEMPLATE_r21 623 -#define _BUILD_TUPLE_r01 624 -#define _CALL_BUILTIN_CLASS_r01 625 -#define _CALL_BUILTIN_FAST_r01 626 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 627 -#define _CALL_BUILTIN_O_r03 628 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 629 -#define _CALL_INTRINSIC_1_r11 630 -#define _CALL_INTRINSIC_2_r21 631 -#define _CALL_ISINSTANCE_r31 632 -#define _CALL_KW_NON_PY_r11 633 -#define _CALL_LEN_r33 634 -#define _CALL_LIST_APPEND_r03 635 -#define _CALL_LIST_APPEND_r13 636 -#define _CALL_LIST_APPEND_r23 637 -#define _CALL_LIST_APPEND_r33 638 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 639 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 640 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 641 -#define _CALL_METHOD_DESCRIPTOR_O_r03 642 -#define _CALL_NON_PY_GENERAL_r01 643 -#define _CALL_STR_1_r32 644 -#define _CALL_TUPLE_1_r32 645 -#define _CALL_TYPE_1_r02 646 -#define _CALL_TYPE_1_r12 647 -#define _CALL_TYPE_1_r22 648 -#define _CALL_TYPE_1_r32 649 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 650 -#define _CHECK_ATTR_CLASS_r01 651 -#define _CHECK_ATTR_CLASS_r11 652 -#define _CHECK_ATTR_CLASS_r22 653 -#define _CHECK_ATTR_CLASS_r33 654 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 655 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 656 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 657 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 658 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 659 -#define _CHECK_EG_MATCH_r22 660 -#define _CHECK_EXC_MATCH_r22 661 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 662 -#define _CHECK_FUNCTION_VERSION_r00 663 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 664 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 665 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 666 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 667 -#define _CHECK_FUNCTION_VERSION_KW_r11 668 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 669 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 670 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 671 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 672 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 673 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 674 -#define _CHECK_IS_PY_CALLABLE_EX_r03 675 -#define _CHECK_IS_PY_CALLABLE_EX_r13 676 -#define _CHECK_IS_PY_CALLABLE_EX_r23 677 -#define _CHECK_IS_PY_CALLABLE_EX_r33 678 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 679 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 680 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 681 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 682 -#define _CHECK_METHOD_VERSION_r00 683 -#define _CHECK_METHOD_VERSION_KW_r11 684 -#define _CHECK_PEP_523_r00 685 -#define _CHECK_PEP_523_r11 686 -#define _CHECK_PEP_523_r22 687 -#define _CHECK_PEP_523_r33 688 -#define _CHECK_PERIODIC_r00 689 -#define _CHECK_PERIODIC_AT_END_r00 690 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 691 -#define _CHECK_RECURSION_REMAINING_r00 692 -#define _CHECK_RECURSION_REMAINING_r11 693 -#define _CHECK_RECURSION_REMAINING_r22 694 -#define _CHECK_RECURSION_REMAINING_r33 695 -#define _CHECK_STACK_SPACE_r00 696 -#define _CHECK_STACK_SPACE_OPERAND_r00 697 -#define _CHECK_STACK_SPACE_OPERAND_r11 698 -#define _CHECK_STACK_SPACE_OPERAND_r22 699 -#define _CHECK_STACK_SPACE_OPERAND_r33 700 -#define _CHECK_VALIDITY_r00 701 -#define _CHECK_VALIDITY_r11 702 -#define _CHECK_VALIDITY_r22 703 -#define _CHECK_VALIDITY_r33 704 -#define _COLD_DYNAMIC_EXIT_r00 705 -#define _COLD_EXIT_r00 706 -#define _COMPARE_OP_r21 707 -#define _COMPARE_OP_FLOAT_r03 708 -#define _COMPARE_OP_FLOAT_r13 709 -#define _COMPARE_OP_FLOAT_r23 710 -#define _COMPARE_OP_INT_r23 711 -#define _COMPARE_OP_STR_r23 712 -#define _CONTAINS_OP_r23 713 -#define _CONTAINS_OP_DICT_r23 714 -#define _CONTAINS_OP_SET_r23 715 -#define _CONVERT_VALUE_r11 716 -#define _COPY_r01 717 -#define _COPY_1_r02 718 -#define _COPY_1_r12 719 -#define _COPY_1_r23 720 -#define _COPY_2_r03 721 -#define _COPY_2_r13 722 -#define _COPY_2_r23 723 -#define _COPY_3_r03 724 -#define _COPY_3_r13 725 -#define _COPY_3_r23 726 -#define _COPY_3_r33 727 -#define _COPY_FREE_VARS_r00 728 -#define _COPY_FREE_VARS_r11 729 -#define _COPY_FREE_VARS_r22 730 -#define _COPY_FREE_VARS_r33 731 -#define _CREATE_INIT_FRAME_r01 732 -#define _DELETE_ATTR_r10 733 -#define _DELETE_DEREF_r00 734 -#define _DELETE_FAST_r00 735 -#define _DELETE_GLOBAL_r00 736 -#define _DELETE_NAME_r00 737 -#define _DELETE_SUBSCR_r20 738 -#define _DEOPT_r00 739 -#define _DEOPT_r10 740 -#define _DEOPT_r20 741 -#define _DEOPT_r30 742 -#define _DICT_MERGE_r10 743 -#define _DICT_UPDATE_r10 744 -#define _DO_CALL_r01 745 -#define _DO_CALL_FUNCTION_EX_r31 746 -#define _DO_CALL_KW_r11 747 -#define _DYNAMIC_EXIT_r00 748 -#define _DYNAMIC_EXIT_r10 749 -#define _DYNAMIC_EXIT_r20 750 -#define _DYNAMIC_EXIT_r30 751 -#define _END_FOR_r10 752 -#define _END_SEND_r21 753 -#define _ERROR_POP_N_r00 754 -#define _EXIT_INIT_CHECK_r10 755 -#define _EXIT_TRACE_r00 756 -#define _EXIT_TRACE_r10 757 -#define _EXIT_TRACE_r20 758 -#define _EXIT_TRACE_r30 759 -#define _EXPAND_METHOD_r00 760 -#define _EXPAND_METHOD_KW_r11 761 -#define _FATAL_ERROR_r00 762 -#define _FATAL_ERROR_r11 763 -#define _FATAL_ERROR_r22 764 -#define _FATAL_ERROR_r33 765 -#define _FORMAT_SIMPLE_r11 766 -#define _FORMAT_WITH_SPEC_r21 767 -#define _FOR_ITER_r23 768 -#define _FOR_ITER_GEN_FRAME_r03 769 -#define _FOR_ITER_GEN_FRAME_r13 770 -#define _FOR_ITER_GEN_FRAME_r23 771 -#define _FOR_ITER_TIER_TWO_r23 772 -#define _GET_AITER_r11 773 -#define _GET_ANEXT_r12 774 -#define _GET_AWAITABLE_r11 775 -#define _GET_ITER_r12 776 -#define _GET_LEN_r12 777 -#define _GET_YIELD_FROM_ITER_r11 778 -#define _GUARD_BINARY_OP_EXTEND_r22 779 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 780 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 781 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 782 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 783 -#define _GUARD_BIT_IS_SET_POP_r00 784 -#define _GUARD_BIT_IS_SET_POP_r10 785 -#define _GUARD_BIT_IS_SET_POP_r21 786 -#define _GUARD_BIT_IS_SET_POP_r32 787 -#define _GUARD_BIT_IS_SET_POP_4_r00 788 -#define _GUARD_BIT_IS_SET_POP_4_r10 789 -#define _GUARD_BIT_IS_SET_POP_4_r21 790 -#define _GUARD_BIT_IS_SET_POP_4_r32 791 -#define _GUARD_BIT_IS_SET_POP_5_r00 792 -#define _GUARD_BIT_IS_SET_POP_5_r10 793 -#define _GUARD_BIT_IS_SET_POP_5_r21 794 -#define _GUARD_BIT_IS_SET_POP_5_r32 795 -#define _GUARD_BIT_IS_SET_POP_6_r00 796 -#define _GUARD_BIT_IS_SET_POP_6_r10 797 -#define _GUARD_BIT_IS_SET_POP_6_r21 798 -#define _GUARD_BIT_IS_SET_POP_6_r32 799 -#define _GUARD_BIT_IS_SET_POP_7_r00 800 -#define _GUARD_BIT_IS_SET_POP_7_r10 801 -#define _GUARD_BIT_IS_SET_POP_7_r21 802 -#define _GUARD_BIT_IS_SET_POP_7_r32 803 -#define _GUARD_BIT_IS_UNSET_POP_r00 804 -#define _GUARD_BIT_IS_UNSET_POP_r10 805 -#define _GUARD_BIT_IS_UNSET_POP_r21 806 -#define _GUARD_BIT_IS_UNSET_POP_r32 807 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 808 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 809 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 810 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 811 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 812 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 813 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 814 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 815 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 816 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 817 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 818 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 819 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 820 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 821 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 822 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 823 -#define _GUARD_CALLABLE_ISINSTANCE_r03 824 -#define _GUARD_CALLABLE_ISINSTANCE_r13 825 -#define _GUARD_CALLABLE_ISINSTANCE_r23 826 -#define _GUARD_CALLABLE_ISINSTANCE_r33 827 -#define _GUARD_CALLABLE_LEN_r03 828 -#define _GUARD_CALLABLE_LEN_r13 829 -#define _GUARD_CALLABLE_LEN_r23 830 -#define _GUARD_CALLABLE_LEN_r33 831 -#define _GUARD_CALLABLE_LIST_APPEND_r03 832 -#define _GUARD_CALLABLE_LIST_APPEND_r13 833 -#define _GUARD_CALLABLE_LIST_APPEND_r23 834 -#define _GUARD_CALLABLE_LIST_APPEND_r33 835 -#define _GUARD_CALLABLE_STR_1_r03 836 -#define _GUARD_CALLABLE_STR_1_r13 837 -#define _GUARD_CALLABLE_STR_1_r23 838 -#define _GUARD_CALLABLE_STR_1_r33 839 -#define _GUARD_CALLABLE_TUPLE_1_r03 840 -#define _GUARD_CALLABLE_TUPLE_1_r13 841 -#define _GUARD_CALLABLE_TUPLE_1_r23 842 -#define _GUARD_CALLABLE_TUPLE_1_r33 843 -#define _GUARD_CALLABLE_TYPE_1_r03 844 -#define _GUARD_CALLABLE_TYPE_1_r13 845 -#define _GUARD_CALLABLE_TYPE_1_r23 846 -#define _GUARD_CALLABLE_TYPE_1_r33 847 -#define _GUARD_DORV_NO_DICT_r01 848 -#define _GUARD_DORV_NO_DICT_r11 849 -#define _GUARD_DORV_NO_DICT_r22 850 -#define _GUARD_DORV_NO_DICT_r33 851 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 852 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 853 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 854 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 855 -#define _GUARD_GLOBALS_VERSION_r00 856 -#define _GUARD_GLOBALS_VERSION_r11 857 -#define _GUARD_GLOBALS_VERSION_r22 858 -#define _GUARD_GLOBALS_VERSION_r33 859 -#define _GUARD_IP_RETURN_GENERATOR_r00 860 -#define _GUARD_IP_RETURN_GENERATOR_r11 861 -#define _GUARD_IP_RETURN_GENERATOR_r22 862 -#define _GUARD_IP_RETURN_GENERATOR_r33 863 -#define _GUARD_IP_RETURN_VALUE_r00 864 -#define _GUARD_IP_RETURN_VALUE_r11 865 -#define _GUARD_IP_RETURN_VALUE_r22 866 -#define _GUARD_IP_RETURN_VALUE_r33 867 -#define _GUARD_IP_YIELD_VALUE_r00 868 -#define _GUARD_IP_YIELD_VALUE_r11 869 -#define _GUARD_IP_YIELD_VALUE_r22 870 -#define _GUARD_IP_YIELD_VALUE_r33 871 -#define _GUARD_IP__PUSH_FRAME_r00 872 -#define _GUARD_IP__PUSH_FRAME_r11 873 -#define _GUARD_IP__PUSH_FRAME_r22 874 -#define _GUARD_IP__PUSH_FRAME_r33 875 -#define _GUARD_IS_FALSE_POP_r00 876 -#define _GUARD_IS_FALSE_POP_r10 877 -#define _GUARD_IS_FALSE_POP_r21 878 -#define _GUARD_IS_FALSE_POP_r32 879 -#define _GUARD_IS_NONE_POP_r00 880 -#define _GUARD_IS_NONE_POP_r10 881 -#define _GUARD_IS_NONE_POP_r21 882 -#define _GUARD_IS_NONE_POP_r32 883 -#define _GUARD_IS_NOT_NONE_POP_r10 884 -#define _GUARD_IS_TRUE_POP_r00 885 -#define _GUARD_IS_TRUE_POP_r10 886 -#define _GUARD_IS_TRUE_POP_r21 887 -#define _GUARD_IS_TRUE_POP_r32 888 -#define _GUARD_KEYS_VERSION_r01 889 -#define _GUARD_KEYS_VERSION_r11 890 -#define _GUARD_KEYS_VERSION_r22 891 -#define _GUARD_KEYS_VERSION_r33 892 -#define _GUARD_NOS_COMPACT_ASCII_r02 893 -#define _GUARD_NOS_COMPACT_ASCII_r12 894 -#define _GUARD_NOS_COMPACT_ASCII_r22 895 -#define _GUARD_NOS_COMPACT_ASCII_r33 896 -#define _GUARD_NOS_DICT_r02 897 -#define _GUARD_NOS_DICT_r12 898 -#define _GUARD_NOS_DICT_r22 899 -#define _GUARD_NOS_DICT_r33 900 -#define _GUARD_NOS_FLOAT_r02 901 -#define _GUARD_NOS_FLOAT_r12 902 -#define _GUARD_NOS_FLOAT_r22 903 -#define _GUARD_NOS_FLOAT_r33 904 -#define _GUARD_NOS_INT_r02 905 -#define _GUARD_NOS_INT_r12 906 -#define _GUARD_NOS_INT_r22 907 -#define _GUARD_NOS_INT_r33 908 -#define _GUARD_NOS_LIST_r02 909 -#define _GUARD_NOS_LIST_r12 910 -#define _GUARD_NOS_LIST_r22 911 -#define _GUARD_NOS_LIST_r33 912 -#define _GUARD_NOS_NOT_NULL_r02 913 -#define _GUARD_NOS_NOT_NULL_r12 914 -#define _GUARD_NOS_NOT_NULL_r22 915 -#define _GUARD_NOS_NOT_NULL_r33 916 -#define _GUARD_NOS_NULL_r02 917 -#define _GUARD_NOS_NULL_r12 918 -#define _GUARD_NOS_NULL_r22 919 -#define _GUARD_NOS_NULL_r33 920 -#define _GUARD_NOS_OVERFLOWED_r02 921 -#define _GUARD_NOS_OVERFLOWED_r12 922 -#define _GUARD_NOS_OVERFLOWED_r22 923 -#define _GUARD_NOS_OVERFLOWED_r33 924 -#define _GUARD_NOS_TUPLE_r02 925 -#define _GUARD_NOS_TUPLE_r12 926 -#define _GUARD_NOS_TUPLE_r22 927 -#define _GUARD_NOS_TUPLE_r33 928 -#define _GUARD_NOS_UNICODE_r02 929 -#define _GUARD_NOS_UNICODE_r12 930 -#define _GUARD_NOS_UNICODE_r22 931 -#define _GUARD_NOS_UNICODE_r33 932 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 933 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 934 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 935 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 936 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 937 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 938 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 939 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 940 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 941 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 942 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 943 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 944 -#define _GUARD_THIRD_NULL_r03 945 -#define _GUARD_THIRD_NULL_r13 946 -#define _GUARD_THIRD_NULL_r23 947 -#define _GUARD_THIRD_NULL_r33 948 -#define _GUARD_TOS_ANY_SET_r01 949 -#define _GUARD_TOS_ANY_SET_r11 950 -#define _GUARD_TOS_ANY_SET_r22 951 -#define _GUARD_TOS_ANY_SET_r33 952 -#define _GUARD_TOS_DICT_r01 953 -#define _GUARD_TOS_DICT_r11 954 -#define _GUARD_TOS_DICT_r22 955 -#define _GUARD_TOS_DICT_r33 956 -#define _GUARD_TOS_FLOAT_r01 957 -#define _GUARD_TOS_FLOAT_r11 958 -#define _GUARD_TOS_FLOAT_r22 959 -#define _GUARD_TOS_FLOAT_r33 960 -#define _GUARD_TOS_INT_r01 961 -#define _GUARD_TOS_INT_r11 962 -#define _GUARD_TOS_INT_r22 963 -#define _GUARD_TOS_INT_r33 964 -#define _GUARD_TOS_LIST_r01 965 -#define _GUARD_TOS_LIST_r11 966 -#define _GUARD_TOS_LIST_r22 967 -#define _GUARD_TOS_LIST_r33 968 -#define _GUARD_TOS_OVERFLOWED_r01 969 -#define _GUARD_TOS_OVERFLOWED_r11 970 -#define _GUARD_TOS_OVERFLOWED_r22 971 -#define _GUARD_TOS_OVERFLOWED_r33 972 -#define _GUARD_TOS_SLICE_r01 973 -#define _GUARD_TOS_SLICE_r11 974 -#define _GUARD_TOS_SLICE_r22 975 -#define _GUARD_TOS_SLICE_r33 976 -#define _GUARD_TOS_TUPLE_r01 977 -#define _GUARD_TOS_TUPLE_r11 978 -#define _GUARD_TOS_TUPLE_r22 979 -#define _GUARD_TOS_TUPLE_r33 980 -#define _GUARD_TOS_UNICODE_r01 981 -#define _GUARD_TOS_UNICODE_r11 982 -#define _GUARD_TOS_UNICODE_r22 983 -#define _GUARD_TOS_UNICODE_r33 984 -#define _GUARD_TYPE_VERSION_r01 985 -#define _GUARD_TYPE_VERSION_r11 986 -#define _GUARD_TYPE_VERSION_r22 987 -#define _GUARD_TYPE_VERSION_r33 988 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 989 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 990 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 991 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 992 -#define _HANDLE_PENDING_AND_DEOPT_r00 993 -#define _HANDLE_PENDING_AND_DEOPT_r10 994 -#define _HANDLE_PENDING_AND_DEOPT_r20 995 -#define _HANDLE_PENDING_AND_DEOPT_r30 996 -#define _IMPORT_FROM_r12 997 -#define _IMPORT_NAME_r21 998 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 999 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1000 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1001 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1002 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1003 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1004 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1005 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1006 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1007 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1008 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1009 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1010 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1011 -#define _INSERT_NULL_r10 1012 -#define _INSTRUMENTED_FOR_ITER_r23 1013 -#define _INSTRUMENTED_INSTRUCTION_r00 1014 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1015 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1016 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1017 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1018 -#define _INSTRUMENTED_LINE_r00 1019 -#define _INSTRUMENTED_NOT_TAKEN_r00 1020 -#define _INSTRUMENTED_NOT_TAKEN_r11 1021 -#define _INSTRUMENTED_NOT_TAKEN_r22 1022 -#define _INSTRUMENTED_NOT_TAKEN_r33 1023 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1024 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1025 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1026 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1027 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1028 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1029 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1030 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1031 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1032 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1033 -#define _IS_NONE_r11 1034 -#define _IS_OP_r03 1035 -#define _IS_OP_r13 1036 -#define _IS_OP_r23 1037 -#define _ITER_CHECK_LIST_r02 1038 -#define _ITER_CHECK_LIST_r12 1039 -#define _ITER_CHECK_LIST_r22 1040 -#define _ITER_CHECK_LIST_r33 1041 -#define _ITER_CHECK_RANGE_r02 1042 -#define _ITER_CHECK_RANGE_r12 1043 -#define _ITER_CHECK_RANGE_r22 1044 -#define _ITER_CHECK_RANGE_r33 1045 -#define _ITER_CHECK_TUPLE_r02 1046 -#define _ITER_CHECK_TUPLE_r12 1047 -#define _ITER_CHECK_TUPLE_r22 1048 -#define _ITER_CHECK_TUPLE_r33 1049 -#define _ITER_JUMP_LIST_r02 1050 -#define _ITER_JUMP_LIST_r12 1051 -#define _ITER_JUMP_LIST_r22 1052 -#define _ITER_JUMP_LIST_r33 1053 -#define _ITER_JUMP_RANGE_r02 1054 -#define _ITER_JUMP_RANGE_r12 1055 -#define _ITER_JUMP_RANGE_r22 1056 -#define _ITER_JUMP_RANGE_r33 1057 -#define _ITER_JUMP_TUPLE_r02 1058 -#define _ITER_JUMP_TUPLE_r12 1059 -#define _ITER_JUMP_TUPLE_r22 1060 -#define _ITER_JUMP_TUPLE_r33 1061 -#define _ITER_NEXT_LIST_r23 1062 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1063 -#define _ITER_NEXT_RANGE_r03 1064 -#define _ITER_NEXT_RANGE_r13 1065 -#define _ITER_NEXT_RANGE_r23 1066 -#define _ITER_NEXT_TUPLE_r03 1067 -#define _ITER_NEXT_TUPLE_r13 1068 -#define _ITER_NEXT_TUPLE_r23 1069 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1070 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1071 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1072 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1073 -#define _JUMP_TO_TOP_r00 1074 -#define _LIST_APPEND_r10 1075 -#define _LIST_EXTEND_r10 1076 -#define _LOAD_ATTR_r10 1077 -#define _LOAD_ATTR_CLASS_r11 1078 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1079 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1080 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1081 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1082 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1083 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1084 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1085 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1086 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1087 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1088 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1089 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1090 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1091 -#define _LOAD_ATTR_MODULE_r11 1092 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1093 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1094 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1095 -#define _LOAD_ATTR_SLOT_r02 1096 -#define _LOAD_ATTR_SLOT_r12 1097 -#define _LOAD_ATTR_SLOT_r23 1098 -#define _LOAD_ATTR_WITH_HINT_r12 1099 -#define _LOAD_BUILD_CLASS_r01 1100 -#define _LOAD_BYTECODE_r00 1101 -#define _LOAD_COMMON_CONSTANT_r01 1102 -#define _LOAD_COMMON_CONSTANT_r12 1103 -#define _LOAD_COMMON_CONSTANT_r23 1104 -#define _LOAD_CONST_r01 1105 -#define _LOAD_CONST_r12 1106 -#define _LOAD_CONST_r23 1107 -#define _LOAD_CONST_INLINE_r01 1108 -#define _LOAD_CONST_INLINE_r12 1109 -#define _LOAD_CONST_INLINE_r23 1110 -#define _LOAD_CONST_INLINE_BORROW_r01 1111 -#define _LOAD_CONST_INLINE_BORROW_r12 1112 -#define _LOAD_CONST_INLINE_BORROW_r23 1113 -#define _LOAD_CONST_UNDER_INLINE_r02 1114 -#define _LOAD_CONST_UNDER_INLINE_r12 1115 -#define _LOAD_CONST_UNDER_INLINE_r23 1116 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1117 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1118 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1119 -#define _LOAD_DEREF_r01 1120 -#define _LOAD_FAST_r01 1121 -#define _LOAD_FAST_r12 1122 -#define _LOAD_FAST_r23 1123 -#define _LOAD_FAST_0_r01 1124 -#define _LOAD_FAST_0_r12 1125 -#define _LOAD_FAST_0_r23 1126 -#define _LOAD_FAST_1_r01 1127 -#define _LOAD_FAST_1_r12 1128 -#define _LOAD_FAST_1_r23 1129 -#define _LOAD_FAST_2_r01 1130 -#define _LOAD_FAST_2_r12 1131 -#define _LOAD_FAST_2_r23 1132 -#define _LOAD_FAST_3_r01 1133 -#define _LOAD_FAST_3_r12 1134 -#define _LOAD_FAST_3_r23 1135 -#define _LOAD_FAST_4_r01 1136 -#define _LOAD_FAST_4_r12 1137 -#define _LOAD_FAST_4_r23 1138 -#define _LOAD_FAST_5_r01 1139 -#define _LOAD_FAST_5_r12 1140 -#define _LOAD_FAST_5_r23 1141 -#define _LOAD_FAST_6_r01 1142 -#define _LOAD_FAST_6_r12 1143 -#define _LOAD_FAST_6_r23 1144 -#define _LOAD_FAST_7_r01 1145 -#define _LOAD_FAST_7_r12 1146 -#define _LOAD_FAST_7_r23 1147 -#define _LOAD_FAST_AND_CLEAR_r01 1148 -#define _LOAD_FAST_AND_CLEAR_r12 1149 -#define _LOAD_FAST_AND_CLEAR_r23 1150 -#define _LOAD_FAST_BORROW_r01 1151 -#define _LOAD_FAST_BORROW_r12 1152 -#define _LOAD_FAST_BORROW_r23 1153 -#define _LOAD_FAST_BORROW_0_r01 1154 -#define _LOAD_FAST_BORROW_0_r12 1155 -#define _LOAD_FAST_BORROW_0_r23 1156 -#define _LOAD_FAST_BORROW_1_r01 1157 -#define _LOAD_FAST_BORROW_1_r12 1158 -#define _LOAD_FAST_BORROW_1_r23 1159 -#define _LOAD_FAST_BORROW_2_r01 1160 -#define _LOAD_FAST_BORROW_2_r12 1161 -#define _LOAD_FAST_BORROW_2_r23 1162 -#define _LOAD_FAST_BORROW_3_r01 1163 -#define _LOAD_FAST_BORROW_3_r12 1164 -#define _LOAD_FAST_BORROW_3_r23 1165 -#define _LOAD_FAST_BORROW_4_r01 1166 -#define _LOAD_FAST_BORROW_4_r12 1167 -#define _LOAD_FAST_BORROW_4_r23 1168 -#define _LOAD_FAST_BORROW_5_r01 1169 -#define _LOAD_FAST_BORROW_5_r12 1170 -#define _LOAD_FAST_BORROW_5_r23 1171 -#define _LOAD_FAST_BORROW_6_r01 1172 -#define _LOAD_FAST_BORROW_6_r12 1173 -#define _LOAD_FAST_BORROW_6_r23 1174 -#define _LOAD_FAST_BORROW_7_r01 1175 -#define _LOAD_FAST_BORROW_7_r12 1176 -#define _LOAD_FAST_BORROW_7_r23 1177 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1178 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1179 -#define _LOAD_FAST_CHECK_r01 1180 -#define _LOAD_FAST_CHECK_r12 1181 -#define _LOAD_FAST_CHECK_r23 1182 -#define _LOAD_FAST_LOAD_FAST_r02 1183 -#define _LOAD_FAST_LOAD_FAST_r13 1184 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1185 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1186 -#define _LOAD_GLOBAL_r00 1187 -#define _LOAD_GLOBAL_BUILTINS_r01 1188 -#define _LOAD_GLOBAL_MODULE_r01 1189 -#define _LOAD_LOCALS_r01 1190 -#define _LOAD_LOCALS_r12 1191 -#define _LOAD_LOCALS_r23 1192 -#define _LOAD_NAME_r01 1193 -#define _LOAD_SMALL_INT_r01 1194 -#define _LOAD_SMALL_INT_r12 1195 -#define _LOAD_SMALL_INT_r23 1196 -#define _LOAD_SMALL_INT_0_r01 1197 -#define _LOAD_SMALL_INT_0_r12 1198 -#define _LOAD_SMALL_INT_0_r23 1199 -#define _LOAD_SMALL_INT_1_r01 1200 -#define _LOAD_SMALL_INT_1_r12 1201 -#define _LOAD_SMALL_INT_1_r23 1202 -#define _LOAD_SMALL_INT_2_r01 1203 -#define _LOAD_SMALL_INT_2_r12 1204 -#define _LOAD_SMALL_INT_2_r23 1205 -#define _LOAD_SMALL_INT_3_r01 1206 -#define _LOAD_SMALL_INT_3_r12 1207 -#define _LOAD_SMALL_INT_3_r23 1208 -#define _LOAD_SPECIAL_r00 1209 -#define _LOAD_SUPER_ATTR_ATTR_r31 1210 -#define _LOAD_SUPER_ATTR_METHOD_r32 1211 -#define _MAKE_CALLARGS_A_TUPLE_r33 1212 -#define _MAKE_CELL_r00 1213 -#define _MAKE_FUNCTION_r11 1214 -#define _MAKE_WARM_r00 1215 -#define _MAKE_WARM_r11 1216 -#define _MAKE_WARM_r22 1217 -#define _MAKE_WARM_r33 1218 -#define _MAP_ADD_r20 1219 -#define _MATCH_CLASS_r31 1220 -#define _MATCH_KEYS_r23 1221 -#define _MATCH_MAPPING_r02 1222 -#define _MATCH_MAPPING_r12 1223 -#define _MATCH_MAPPING_r23 1224 -#define _MATCH_SEQUENCE_r02 1225 -#define _MATCH_SEQUENCE_r12 1226 -#define _MATCH_SEQUENCE_r23 1227 -#define _MAYBE_EXPAND_METHOD_r00 1228 -#define _MAYBE_EXPAND_METHOD_KW_r11 1229 -#define _MONITOR_CALL_r00 1230 -#define _MONITOR_CALL_KW_r11 1231 -#define _MONITOR_JUMP_BACKWARD_r00 1232 -#define _MONITOR_JUMP_BACKWARD_r11 1233 -#define _MONITOR_JUMP_BACKWARD_r22 1234 -#define _MONITOR_JUMP_BACKWARD_r33 1235 -#define _MONITOR_RESUME_r00 1236 -#define _NOP_r00 1237 -#define _NOP_r11 1238 -#define _NOP_r22 1239 -#define _NOP_r33 1240 -#define _POP_CALL_r20 1241 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1242 -#define _POP_CALL_ONE_r30 1243 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1244 -#define _POP_CALL_TWO_r30 1245 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1246 -#define _POP_EXCEPT_r10 1247 -#define _POP_ITER_r20 1248 -#define _POP_JUMP_IF_FALSE_r00 1249 -#define _POP_JUMP_IF_FALSE_r10 1250 -#define _POP_JUMP_IF_FALSE_r21 1251 -#define _POP_JUMP_IF_FALSE_r32 1252 -#define _POP_JUMP_IF_TRUE_r00 1253 -#define _POP_JUMP_IF_TRUE_r10 1254 -#define _POP_JUMP_IF_TRUE_r21 1255 -#define _POP_JUMP_IF_TRUE_r32 1256 -#define _POP_TOP_r10 1257 -#define _POP_TOP_FLOAT_r00 1258 -#define _POP_TOP_FLOAT_r10 1259 -#define _POP_TOP_FLOAT_r21 1260 -#define _POP_TOP_FLOAT_r32 1261 -#define _POP_TOP_INT_r00 1262 -#define _POP_TOP_INT_r10 1263 -#define _POP_TOP_INT_r21 1264 -#define _POP_TOP_INT_r32 1265 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1266 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1267 -#define _POP_TOP_NOP_r00 1268 -#define _POP_TOP_NOP_r10 1269 -#define _POP_TOP_NOP_r21 1270 -#define _POP_TOP_NOP_r32 1271 -#define _POP_TOP_UNICODE_r00 1272 -#define _POP_TOP_UNICODE_r10 1273 -#define _POP_TOP_UNICODE_r21 1274 -#define _POP_TOP_UNICODE_r32 1275 -#define _POP_TWO_r20 1276 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1277 -#define _PUSH_EXC_INFO_r02 1278 -#define _PUSH_EXC_INFO_r12 1279 -#define _PUSH_EXC_INFO_r23 1280 -#define _PUSH_FRAME_r10 1281 -#define _PUSH_NULL_r01 1282 -#define _PUSH_NULL_r12 1283 -#define _PUSH_NULL_r23 1284 -#define _PUSH_NULL_CONDITIONAL_r00 1285 -#define _PY_FRAME_EX_r31 1286 -#define _PY_FRAME_GENERAL_r01 1287 -#define _PY_FRAME_KW_r11 1288 -#define _QUICKEN_RESUME_r00 1289 -#define _QUICKEN_RESUME_r11 1290 -#define _QUICKEN_RESUME_r22 1291 -#define _QUICKEN_RESUME_r33 1292 -#define _REPLACE_WITH_TRUE_r02 1293 -#define _REPLACE_WITH_TRUE_r12 1294 -#define _REPLACE_WITH_TRUE_r23 1295 -#define _RESUME_CHECK_r00 1296 -#define _RESUME_CHECK_r11 1297 -#define _RESUME_CHECK_r22 1298 -#define _RESUME_CHECK_r33 1299 -#define _RETURN_GENERATOR_r01 1300 -#define _RETURN_VALUE_r11 1301 -#define _SAVE_RETURN_OFFSET_r00 1302 -#define _SAVE_RETURN_OFFSET_r11 1303 -#define _SAVE_RETURN_OFFSET_r22 1304 -#define _SAVE_RETURN_OFFSET_r33 1305 -#define _SEND_r22 1306 -#define _SEND_GEN_FRAME_r22 1307 -#define _SETUP_ANNOTATIONS_r00 1308 -#define _SET_ADD_r10 1309 -#define _SET_FUNCTION_ATTRIBUTE_r01 1310 -#define _SET_FUNCTION_ATTRIBUTE_r11 1311 -#define _SET_FUNCTION_ATTRIBUTE_r21 1312 -#define _SET_FUNCTION_ATTRIBUTE_r32 1313 -#define _SET_IP_r00 1314 -#define _SET_IP_r11 1315 -#define _SET_IP_r22 1316 -#define _SET_IP_r33 1317 -#define _SET_UPDATE_r10 1318 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1319 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1320 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1321 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1322 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1323 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1324 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1325 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1326 -#define _SPILL_OR_RELOAD_r01 1327 -#define _SPILL_OR_RELOAD_r02 1328 -#define _SPILL_OR_RELOAD_r03 1329 -#define _SPILL_OR_RELOAD_r10 1330 -#define _SPILL_OR_RELOAD_r12 1331 -#define _SPILL_OR_RELOAD_r13 1332 -#define _SPILL_OR_RELOAD_r20 1333 -#define _SPILL_OR_RELOAD_r21 1334 -#define _SPILL_OR_RELOAD_r23 1335 -#define _SPILL_OR_RELOAD_r30 1336 -#define _SPILL_OR_RELOAD_r31 1337 -#define _SPILL_OR_RELOAD_r32 1338 -#define _START_EXECUTOR_r00 1339 -#define _STORE_ATTR_r20 1340 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1341 -#define _STORE_ATTR_SLOT_r21 1342 -#define _STORE_ATTR_WITH_HINT_r21 1343 -#define _STORE_DEREF_r10 1344 -#define _STORE_FAST_LOAD_FAST_r11 1345 -#define _STORE_FAST_STORE_FAST_r20 1346 -#define _STORE_GLOBAL_r10 1347 -#define _STORE_NAME_r10 1348 -#define _STORE_SLICE_r30 1349 -#define _STORE_SUBSCR_r30 1350 -#define _STORE_SUBSCR_DICT_r31 1351 -#define _STORE_SUBSCR_LIST_INT_r32 1352 -#define _SWAP_r11 1353 -#define _SWAP_2_r02 1354 -#define _SWAP_2_r12 1355 -#define _SWAP_2_r22 1356 -#define _SWAP_2_r33 1357 -#define _SWAP_3_r03 1358 -#define _SWAP_3_r13 1359 -#define _SWAP_3_r23 1360 -#define _SWAP_3_r33 1361 -#define _SWAP_FAST_r01 1362 -#define _SWAP_FAST_r11 1363 -#define _SWAP_FAST_r22 1364 -#define _SWAP_FAST_r33 1365 -#define _SWAP_FAST_0_r01 1366 -#define _SWAP_FAST_0_r11 1367 -#define _SWAP_FAST_0_r22 1368 -#define _SWAP_FAST_0_r33 1369 -#define _SWAP_FAST_1_r01 1370 -#define _SWAP_FAST_1_r11 1371 -#define _SWAP_FAST_1_r22 1372 -#define _SWAP_FAST_1_r33 1373 -#define _SWAP_FAST_2_r01 1374 -#define _SWAP_FAST_2_r11 1375 -#define _SWAP_FAST_2_r22 1376 -#define _SWAP_FAST_2_r33 1377 -#define _SWAP_FAST_3_r01 1378 -#define _SWAP_FAST_3_r11 1379 -#define _SWAP_FAST_3_r22 1380 -#define _SWAP_FAST_3_r33 1381 -#define _SWAP_FAST_4_r01 1382 -#define _SWAP_FAST_4_r11 1383 -#define _SWAP_FAST_4_r22 1384 -#define _SWAP_FAST_4_r33 1385 -#define _SWAP_FAST_5_r01 1386 -#define _SWAP_FAST_5_r11 1387 -#define _SWAP_FAST_5_r22 1388 -#define _SWAP_FAST_5_r33 1389 -#define _SWAP_FAST_6_r01 1390 -#define _SWAP_FAST_6_r11 1391 -#define _SWAP_FAST_6_r22 1392 -#define _SWAP_FAST_6_r33 1393 -#define _SWAP_FAST_7_r01 1394 -#define _SWAP_FAST_7_r11 1395 -#define _SWAP_FAST_7_r22 1396 -#define _SWAP_FAST_7_r33 1397 -#define _TIER2_RESUME_CHECK_r00 1398 -#define _TIER2_RESUME_CHECK_r11 1399 -#define _TIER2_RESUME_CHECK_r22 1400 -#define _TIER2_RESUME_CHECK_r33 1401 -#define _TO_BOOL_r11 1402 -#define _TO_BOOL_BOOL_r01 1403 -#define _TO_BOOL_BOOL_r11 1404 -#define _TO_BOOL_BOOL_r22 1405 -#define _TO_BOOL_BOOL_r33 1406 -#define _TO_BOOL_INT_r02 1407 -#define _TO_BOOL_INT_r12 1408 -#define _TO_BOOL_INT_r23 1409 -#define _TO_BOOL_LIST_r02 1410 -#define _TO_BOOL_LIST_r12 1411 -#define _TO_BOOL_LIST_r23 1412 -#define _TO_BOOL_NONE_r01 1413 -#define _TO_BOOL_NONE_r11 1414 -#define _TO_BOOL_NONE_r22 1415 -#define _TO_BOOL_NONE_r33 1416 -#define _TO_BOOL_STR_r02 1417 -#define _TO_BOOL_STR_r12 1418 -#define _TO_BOOL_STR_r23 1419 -#define _TRACE_RECORD_r00 1420 -#define _UNARY_INVERT_r12 1421 -#define _UNARY_NEGATIVE_r12 1422 -#define _UNARY_NOT_r01 1423 -#define _UNARY_NOT_r11 1424 -#define _UNARY_NOT_r22 1425 -#define _UNARY_NOT_r33 1426 -#define _UNPACK_EX_r10 1427 -#define _UNPACK_SEQUENCE_r10 1428 -#define _UNPACK_SEQUENCE_LIST_r10 1429 -#define _UNPACK_SEQUENCE_TUPLE_r10 1430 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1431 -#define _WITH_EXCEPT_START_r33 1432 -#define _YIELD_VALUE_r11 1433 -#define MAX_UOP_REGS_ID 1433 +#define MAX_UOP_ID 579 +#define _BINARY_OP_r23 580 +#define _BINARY_OP_ADD_FLOAT_r03 581 +#define _BINARY_OP_ADD_FLOAT_r13 582 +#define _BINARY_OP_ADD_FLOAT_r23 583 +#define _BINARY_OP_ADD_INT_r03 584 +#define _BINARY_OP_ADD_INT_r13 585 +#define _BINARY_OP_ADD_INT_r23 586 +#define _BINARY_OP_ADD_UNICODE_r03 587 +#define _BINARY_OP_ADD_UNICODE_r13 588 +#define _BINARY_OP_ADD_UNICODE_r23 589 +#define _BINARY_OP_EXTEND_r23 590 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 591 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 592 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 593 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 594 +#define _BINARY_OP_MULTIPLY_INT_r03 595 +#define _BINARY_OP_MULTIPLY_INT_r13 596 +#define _BINARY_OP_MULTIPLY_INT_r23 597 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 598 +#define _BINARY_OP_SUBSCR_DICT_r23 599 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 600 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 601 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 602 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 603 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 604 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 605 +#define _BINARY_OP_SUBSCR_STR_INT_r23 606 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 607 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 608 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 609 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 610 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 611 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 612 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 613 +#define _BINARY_OP_SUBTRACT_INT_r03 614 +#define _BINARY_OP_SUBTRACT_INT_r13 615 +#define _BINARY_OP_SUBTRACT_INT_r23 616 +#define _BINARY_SLICE_r31 617 +#define _BUILD_INTERPOLATION_r01 618 +#define _BUILD_LIST_r01 619 +#define _BUILD_MAP_r01 620 +#define _BUILD_SET_r01 621 +#define _BUILD_SLICE_r01 622 +#define _BUILD_STRING_r01 623 +#define _BUILD_TEMPLATE_r21 624 +#define _BUILD_TUPLE_r01 625 +#define _CALL_BUILTIN_CLASS_r01 626 +#define _CALL_BUILTIN_FAST_r01 627 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 628 +#define _CALL_BUILTIN_O_r03 629 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 630 +#define _CALL_INTRINSIC_1_r11 631 +#define _CALL_INTRINSIC_2_r21 632 +#define _CALL_ISINSTANCE_r31 633 +#define _CALL_KW_NON_PY_r11 634 +#define _CALL_LEN_r33 635 +#define _CALL_LIST_APPEND_r03 636 +#define _CALL_LIST_APPEND_r13 637 +#define _CALL_LIST_APPEND_r23 638 +#define _CALL_LIST_APPEND_r33 639 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 640 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 641 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 642 +#define _CALL_METHOD_DESCRIPTOR_O_r03 643 +#define _CALL_NON_PY_GENERAL_r01 644 +#define _CALL_STR_1_r32 645 +#define _CALL_TUPLE_1_r32 646 +#define _CALL_TYPE_1_r02 647 +#define _CALL_TYPE_1_r12 648 +#define _CALL_TYPE_1_r22 649 +#define _CALL_TYPE_1_r32 650 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 651 +#define _CHECK_ATTR_CLASS_r01 652 +#define _CHECK_ATTR_CLASS_r11 653 +#define _CHECK_ATTR_CLASS_r22 654 +#define _CHECK_ATTR_CLASS_r33 655 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 656 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 657 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 658 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 659 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 660 +#define _CHECK_EG_MATCH_r22 661 +#define _CHECK_EXC_MATCH_r22 662 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 663 +#define _CHECK_FUNCTION_VERSION_r00 664 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 665 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 666 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 667 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 668 +#define _CHECK_FUNCTION_VERSION_KW_r11 669 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 670 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 671 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 672 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 673 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 674 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 675 +#define _CHECK_IS_PY_CALLABLE_EX_r03 676 +#define _CHECK_IS_PY_CALLABLE_EX_r13 677 +#define _CHECK_IS_PY_CALLABLE_EX_r23 678 +#define _CHECK_IS_PY_CALLABLE_EX_r33 679 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 680 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 681 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 682 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 683 +#define _CHECK_METHOD_VERSION_r00 684 +#define _CHECK_METHOD_VERSION_KW_r11 685 +#define _CHECK_PEP_523_r00 686 +#define _CHECK_PEP_523_r11 687 +#define _CHECK_PEP_523_r22 688 +#define _CHECK_PEP_523_r33 689 +#define _CHECK_PERIODIC_r00 690 +#define _CHECK_PERIODIC_AT_END_r00 691 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 692 +#define _CHECK_RECURSION_REMAINING_r00 693 +#define _CHECK_RECURSION_REMAINING_r11 694 +#define _CHECK_RECURSION_REMAINING_r22 695 +#define _CHECK_RECURSION_REMAINING_r33 696 +#define _CHECK_STACK_SPACE_r00 697 +#define _CHECK_STACK_SPACE_OPERAND_r00 698 +#define _CHECK_STACK_SPACE_OPERAND_r11 699 +#define _CHECK_STACK_SPACE_OPERAND_r22 700 +#define _CHECK_STACK_SPACE_OPERAND_r33 701 +#define _CHECK_VALIDITY_r00 702 +#define _CHECK_VALIDITY_r11 703 +#define _CHECK_VALIDITY_r22 704 +#define _CHECK_VALIDITY_r33 705 +#define _COLD_DYNAMIC_EXIT_r00 706 +#define _COLD_EXIT_r00 707 +#define _COMPARE_OP_r21 708 +#define _COMPARE_OP_FLOAT_r03 709 +#define _COMPARE_OP_FLOAT_r13 710 +#define _COMPARE_OP_FLOAT_r23 711 +#define _COMPARE_OP_INT_r23 712 +#define _COMPARE_OP_STR_r23 713 +#define _CONTAINS_OP_r23 714 +#define _CONTAINS_OP_DICT_r23 715 +#define _CONTAINS_OP_SET_r23 716 +#define _CONVERT_VALUE_r11 717 +#define _COPY_r01 718 +#define _COPY_1_r02 719 +#define _COPY_1_r12 720 +#define _COPY_1_r23 721 +#define _COPY_2_r03 722 +#define _COPY_2_r13 723 +#define _COPY_2_r23 724 +#define _COPY_3_r03 725 +#define _COPY_3_r13 726 +#define _COPY_3_r23 727 +#define _COPY_3_r33 728 +#define _COPY_FREE_VARS_r00 729 +#define _COPY_FREE_VARS_r11 730 +#define _COPY_FREE_VARS_r22 731 +#define _COPY_FREE_VARS_r33 732 +#define _CREATE_INIT_FRAME_r01 733 +#define _DELETE_ATTR_r10 734 +#define _DELETE_DEREF_r00 735 +#define _DELETE_FAST_r00 736 +#define _DELETE_GLOBAL_r00 737 +#define _DELETE_NAME_r00 738 +#define _DELETE_SUBSCR_r20 739 +#define _DEOPT_r00 740 +#define _DEOPT_r10 741 +#define _DEOPT_r20 742 +#define _DEOPT_r30 743 +#define _DICT_MERGE_r10 744 +#define _DICT_UPDATE_r10 745 +#define _DO_CALL_r01 746 +#define _DO_CALL_FUNCTION_EX_r31 747 +#define _DO_CALL_KW_r11 748 +#define _DYNAMIC_EXIT_r00 749 +#define _DYNAMIC_EXIT_r10 750 +#define _DYNAMIC_EXIT_r20 751 +#define _DYNAMIC_EXIT_r30 752 +#define _END_FOR_r10 753 +#define _END_SEND_r21 754 +#define _ERROR_POP_N_r00 755 +#define _EXIT_INIT_CHECK_r10 756 +#define _EXIT_TRACE_r00 757 +#define _EXIT_TRACE_r10 758 +#define _EXIT_TRACE_r20 759 +#define _EXIT_TRACE_r30 760 +#define _EXPAND_METHOD_r00 761 +#define _EXPAND_METHOD_KW_r11 762 +#define _FATAL_ERROR_r00 763 +#define _FATAL_ERROR_r11 764 +#define _FATAL_ERROR_r22 765 +#define _FATAL_ERROR_r33 766 +#define _FORMAT_SIMPLE_r11 767 +#define _FORMAT_WITH_SPEC_r21 768 +#define _FOR_ITER_r23 769 +#define _FOR_ITER_GEN_FRAME_r03 770 +#define _FOR_ITER_GEN_FRAME_r13 771 +#define _FOR_ITER_GEN_FRAME_r23 772 +#define _FOR_ITER_TIER_TWO_r23 773 +#define _GET_AITER_r11 774 +#define _GET_ANEXT_r12 775 +#define _GET_AWAITABLE_r11 776 +#define _GET_ITER_r12 777 +#define _GET_LEN_r12 778 +#define _GET_YIELD_FROM_ITER_r11 779 +#define _GUARD_BINARY_OP_EXTEND_r22 780 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 781 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 782 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 783 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 784 +#define _GUARD_BIT_IS_SET_POP_r00 785 +#define _GUARD_BIT_IS_SET_POP_r10 786 +#define _GUARD_BIT_IS_SET_POP_r21 787 +#define _GUARD_BIT_IS_SET_POP_r32 788 +#define _GUARD_BIT_IS_SET_POP_4_r00 789 +#define _GUARD_BIT_IS_SET_POP_4_r10 790 +#define _GUARD_BIT_IS_SET_POP_4_r21 791 +#define _GUARD_BIT_IS_SET_POP_4_r32 792 +#define _GUARD_BIT_IS_SET_POP_5_r00 793 +#define _GUARD_BIT_IS_SET_POP_5_r10 794 +#define _GUARD_BIT_IS_SET_POP_5_r21 795 +#define _GUARD_BIT_IS_SET_POP_5_r32 796 +#define _GUARD_BIT_IS_SET_POP_6_r00 797 +#define _GUARD_BIT_IS_SET_POP_6_r10 798 +#define _GUARD_BIT_IS_SET_POP_6_r21 799 +#define _GUARD_BIT_IS_SET_POP_6_r32 800 +#define _GUARD_BIT_IS_SET_POP_7_r00 801 +#define _GUARD_BIT_IS_SET_POP_7_r10 802 +#define _GUARD_BIT_IS_SET_POP_7_r21 803 +#define _GUARD_BIT_IS_SET_POP_7_r32 804 +#define _GUARD_BIT_IS_UNSET_POP_r00 805 +#define _GUARD_BIT_IS_UNSET_POP_r10 806 +#define _GUARD_BIT_IS_UNSET_POP_r21 807 +#define _GUARD_BIT_IS_UNSET_POP_r32 808 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 809 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 810 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 811 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 812 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 813 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 814 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 815 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 816 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 817 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 818 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 819 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 820 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 821 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 822 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 823 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 824 +#define _GUARD_CALLABLE_ISINSTANCE_r03 825 +#define _GUARD_CALLABLE_ISINSTANCE_r13 826 +#define _GUARD_CALLABLE_ISINSTANCE_r23 827 +#define _GUARD_CALLABLE_ISINSTANCE_r33 828 +#define _GUARD_CALLABLE_LEN_r03 829 +#define _GUARD_CALLABLE_LEN_r13 830 +#define _GUARD_CALLABLE_LEN_r23 831 +#define _GUARD_CALLABLE_LEN_r33 832 +#define _GUARD_CALLABLE_LIST_APPEND_r03 833 +#define _GUARD_CALLABLE_LIST_APPEND_r13 834 +#define _GUARD_CALLABLE_LIST_APPEND_r23 835 +#define _GUARD_CALLABLE_LIST_APPEND_r33 836 +#define _GUARD_CALLABLE_STR_1_r03 837 +#define _GUARD_CALLABLE_STR_1_r13 838 +#define _GUARD_CALLABLE_STR_1_r23 839 +#define _GUARD_CALLABLE_STR_1_r33 840 +#define _GUARD_CALLABLE_TUPLE_1_r03 841 +#define _GUARD_CALLABLE_TUPLE_1_r13 842 +#define _GUARD_CALLABLE_TUPLE_1_r23 843 +#define _GUARD_CALLABLE_TUPLE_1_r33 844 +#define _GUARD_CALLABLE_TYPE_1_r03 845 +#define _GUARD_CALLABLE_TYPE_1_r13 846 +#define _GUARD_CALLABLE_TYPE_1_r23 847 +#define _GUARD_CALLABLE_TYPE_1_r33 848 +#define _GUARD_DORV_NO_DICT_r01 849 +#define _GUARD_DORV_NO_DICT_r11 850 +#define _GUARD_DORV_NO_DICT_r22 851 +#define _GUARD_DORV_NO_DICT_r33 852 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 853 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 854 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 855 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 856 +#define _GUARD_GLOBALS_VERSION_r00 857 +#define _GUARD_GLOBALS_VERSION_r11 858 +#define _GUARD_GLOBALS_VERSION_r22 859 +#define _GUARD_GLOBALS_VERSION_r33 860 +#define _GUARD_IP_RETURN_GENERATOR_r00 861 +#define _GUARD_IP_RETURN_GENERATOR_r11 862 +#define _GUARD_IP_RETURN_GENERATOR_r22 863 +#define _GUARD_IP_RETURN_GENERATOR_r33 864 +#define _GUARD_IP_RETURN_VALUE_r00 865 +#define _GUARD_IP_RETURN_VALUE_r11 866 +#define _GUARD_IP_RETURN_VALUE_r22 867 +#define _GUARD_IP_RETURN_VALUE_r33 868 +#define _GUARD_IP_YIELD_VALUE_r00 869 +#define _GUARD_IP_YIELD_VALUE_r11 870 +#define _GUARD_IP_YIELD_VALUE_r22 871 +#define _GUARD_IP_YIELD_VALUE_r33 872 +#define _GUARD_IP__PUSH_FRAME_r00 873 +#define _GUARD_IP__PUSH_FRAME_r11 874 +#define _GUARD_IP__PUSH_FRAME_r22 875 +#define _GUARD_IP__PUSH_FRAME_r33 876 +#define _GUARD_IS_FALSE_POP_r00 877 +#define _GUARD_IS_FALSE_POP_r10 878 +#define _GUARD_IS_FALSE_POP_r21 879 +#define _GUARD_IS_FALSE_POP_r32 880 +#define _GUARD_IS_NONE_POP_r00 881 +#define _GUARD_IS_NONE_POP_r10 882 +#define _GUARD_IS_NONE_POP_r21 883 +#define _GUARD_IS_NONE_POP_r32 884 +#define _GUARD_IS_NOT_NONE_POP_r10 885 +#define _GUARD_IS_TRUE_POP_r00 886 +#define _GUARD_IS_TRUE_POP_r10 887 +#define _GUARD_IS_TRUE_POP_r21 888 +#define _GUARD_IS_TRUE_POP_r32 889 +#define _GUARD_KEYS_VERSION_r01 890 +#define _GUARD_KEYS_VERSION_r11 891 +#define _GUARD_KEYS_VERSION_r22 892 +#define _GUARD_KEYS_VERSION_r33 893 +#define _GUARD_NOS_COMPACT_ASCII_r02 894 +#define _GUARD_NOS_COMPACT_ASCII_r12 895 +#define _GUARD_NOS_COMPACT_ASCII_r22 896 +#define _GUARD_NOS_COMPACT_ASCII_r33 897 +#define _GUARD_NOS_DICT_r02 898 +#define _GUARD_NOS_DICT_r12 899 +#define _GUARD_NOS_DICT_r22 900 +#define _GUARD_NOS_DICT_r33 901 +#define _GUARD_NOS_FLOAT_r02 902 +#define _GUARD_NOS_FLOAT_r12 903 +#define _GUARD_NOS_FLOAT_r22 904 +#define _GUARD_NOS_FLOAT_r33 905 +#define _GUARD_NOS_INT_r02 906 +#define _GUARD_NOS_INT_r12 907 +#define _GUARD_NOS_INT_r22 908 +#define _GUARD_NOS_INT_r33 909 +#define _GUARD_NOS_LIST_r02 910 +#define _GUARD_NOS_LIST_r12 911 +#define _GUARD_NOS_LIST_r22 912 +#define _GUARD_NOS_LIST_r33 913 +#define _GUARD_NOS_NOT_NULL_r02 914 +#define _GUARD_NOS_NOT_NULL_r12 915 +#define _GUARD_NOS_NOT_NULL_r22 916 +#define _GUARD_NOS_NOT_NULL_r33 917 +#define _GUARD_NOS_NULL_r02 918 +#define _GUARD_NOS_NULL_r12 919 +#define _GUARD_NOS_NULL_r22 920 +#define _GUARD_NOS_NULL_r33 921 +#define _GUARD_NOS_OVERFLOWED_r02 922 +#define _GUARD_NOS_OVERFLOWED_r12 923 +#define _GUARD_NOS_OVERFLOWED_r22 924 +#define _GUARD_NOS_OVERFLOWED_r33 925 +#define _GUARD_NOS_TUPLE_r02 926 +#define _GUARD_NOS_TUPLE_r12 927 +#define _GUARD_NOS_TUPLE_r22 928 +#define _GUARD_NOS_TUPLE_r33 929 +#define _GUARD_NOS_UNICODE_r02 930 +#define _GUARD_NOS_UNICODE_r12 931 +#define _GUARD_NOS_UNICODE_r22 932 +#define _GUARD_NOS_UNICODE_r33 933 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 934 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 935 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 936 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 937 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 938 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 939 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 940 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 941 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 942 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 943 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 944 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 945 +#define _GUARD_THIRD_NULL_r03 946 +#define _GUARD_THIRD_NULL_r13 947 +#define _GUARD_THIRD_NULL_r23 948 +#define _GUARD_THIRD_NULL_r33 949 +#define _GUARD_TOS_ANY_SET_r01 950 +#define _GUARD_TOS_ANY_SET_r11 951 +#define _GUARD_TOS_ANY_SET_r22 952 +#define _GUARD_TOS_ANY_SET_r33 953 +#define _GUARD_TOS_DICT_r01 954 +#define _GUARD_TOS_DICT_r11 955 +#define _GUARD_TOS_DICT_r22 956 +#define _GUARD_TOS_DICT_r33 957 +#define _GUARD_TOS_FLOAT_r01 958 +#define _GUARD_TOS_FLOAT_r11 959 +#define _GUARD_TOS_FLOAT_r22 960 +#define _GUARD_TOS_FLOAT_r33 961 +#define _GUARD_TOS_INT_r01 962 +#define _GUARD_TOS_INT_r11 963 +#define _GUARD_TOS_INT_r22 964 +#define _GUARD_TOS_INT_r33 965 +#define _GUARD_TOS_LIST_r01 966 +#define _GUARD_TOS_LIST_r11 967 +#define _GUARD_TOS_LIST_r22 968 +#define _GUARD_TOS_LIST_r33 969 +#define _GUARD_TOS_OVERFLOWED_r01 970 +#define _GUARD_TOS_OVERFLOWED_r11 971 +#define _GUARD_TOS_OVERFLOWED_r22 972 +#define _GUARD_TOS_OVERFLOWED_r33 973 +#define _GUARD_TOS_SLICE_r01 974 +#define _GUARD_TOS_SLICE_r11 975 +#define _GUARD_TOS_SLICE_r22 976 +#define _GUARD_TOS_SLICE_r33 977 +#define _GUARD_TOS_TUPLE_r01 978 +#define _GUARD_TOS_TUPLE_r11 979 +#define _GUARD_TOS_TUPLE_r22 980 +#define _GUARD_TOS_TUPLE_r33 981 +#define _GUARD_TOS_UNICODE_r01 982 +#define _GUARD_TOS_UNICODE_r11 983 +#define _GUARD_TOS_UNICODE_r22 984 +#define _GUARD_TOS_UNICODE_r33 985 +#define _GUARD_TYPE_VERSION_r01 986 +#define _GUARD_TYPE_VERSION_r11 987 +#define _GUARD_TYPE_VERSION_r22 988 +#define _GUARD_TYPE_VERSION_r33 989 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 990 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 991 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 992 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 993 +#define _HANDLE_PENDING_AND_DEOPT_r00 994 +#define _HANDLE_PENDING_AND_DEOPT_r10 995 +#define _HANDLE_PENDING_AND_DEOPT_r20 996 +#define _HANDLE_PENDING_AND_DEOPT_r30 997 +#define _IMPORT_FROM_r12 998 +#define _IMPORT_NAME_r21 999 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1000 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1001 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1002 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1003 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1004 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1005 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1006 +#define _INSERT_1_LOAD_CONST_INLINE_r02 1007 +#define _INSERT_1_LOAD_CONST_INLINE_r12 1008 +#define _INSERT_1_LOAD_CONST_INLINE_r23 1009 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1010 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1011 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1012 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1013 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1014 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1015 +#define _INSERT_NULL_r10 1016 +#define _INSTRUMENTED_FOR_ITER_r23 1017 +#define _INSTRUMENTED_INSTRUCTION_r00 1018 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1019 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1020 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1021 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1022 +#define _INSTRUMENTED_LINE_r00 1023 +#define _INSTRUMENTED_NOT_TAKEN_r00 1024 +#define _INSTRUMENTED_NOT_TAKEN_r11 1025 +#define _INSTRUMENTED_NOT_TAKEN_r22 1026 +#define _INSTRUMENTED_NOT_TAKEN_r33 1027 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1028 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1029 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1030 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1031 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1032 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1033 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1034 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1035 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1036 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1037 +#define _IS_NONE_r11 1038 +#define _IS_OP_r03 1039 +#define _IS_OP_r13 1040 +#define _IS_OP_r23 1041 +#define _ITER_CHECK_LIST_r02 1042 +#define _ITER_CHECK_LIST_r12 1043 +#define _ITER_CHECK_LIST_r22 1044 +#define _ITER_CHECK_LIST_r33 1045 +#define _ITER_CHECK_RANGE_r02 1046 +#define _ITER_CHECK_RANGE_r12 1047 +#define _ITER_CHECK_RANGE_r22 1048 +#define _ITER_CHECK_RANGE_r33 1049 +#define _ITER_CHECK_TUPLE_r02 1050 +#define _ITER_CHECK_TUPLE_r12 1051 +#define _ITER_CHECK_TUPLE_r22 1052 +#define _ITER_CHECK_TUPLE_r33 1053 +#define _ITER_JUMP_LIST_r02 1054 +#define _ITER_JUMP_LIST_r12 1055 +#define _ITER_JUMP_LIST_r22 1056 +#define _ITER_JUMP_LIST_r33 1057 +#define _ITER_JUMP_RANGE_r02 1058 +#define _ITER_JUMP_RANGE_r12 1059 +#define _ITER_JUMP_RANGE_r22 1060 +#define _ITER_JUMP_RANGE_r33 1061 +#define _ITER_JUMP_TUPLE_r02 1062 +#define _ITER_JUMP_TUPLE_r12 1063 +#define _ITER_JUMP_TUPLE_r22 1064 +#define _ITER_JUMP_TUPLE_r33 1065 +#define _ITER_NEXT_LIST_r23 1066 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1067 +#define _ITER_NEXT_RANGE_r03 1068 +#define _ITER_NEXT_RANGE_r13 1069 +#define _ITER_NEXT_RANGE_r23 1070 +#define _ITER_NEXT_TUPLE_r03 1071 +#define _ITER_NEXT_TUPLE_r13 1072 +#define _ITER_NEXT_TUPLE_r23 1073 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1074 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1075 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1076 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1077 +#define _JUMP_TO_TOP_r00 1078 +#define _LIST_APPEND_r10 1079 +#define _LIST_EXTEND_r10 1080 +#define _LOAD_ATTR_r10 1081 +#define _LOAD_ATTR_CLASS_r11 1082 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1083 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1084 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1085 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1086 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1087 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1088 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1089 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1090 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1091 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1092 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1093 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1094 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1095 +#define _LOAD_ATTR_MODULE_r12 1096 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1097 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1098 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1099 +#define _LOAD_ATTR_SLOT_r02 1100 +#define _LOAD_ATTR_SLOT_r12 1101 +#define _LOAD_ATTR_SLOT_r23 1102 +#define _LOAD_ATTR_WITH_HINT_r12 1103 +#define _LOAD_BUILD_CLASS_r01 1104 +#define _LOAD_BYTECODE_r00 1105 +#define _LOAD_COMMON_CONSTANT_r01 1106 +#define _LOAD_COMMON_CONSTANT_r12 1107 +#define _LOAD_COMMON_CONSTANT_r23 1108 +#define _LOAD_CONST_r01 1109 +#define _LOAD_CONST_r12 1110 +#define _LOAD_CONST_r23 1111 +#define _LOAD_CONST_INLINE_r01 1112 +#define _LOAD_CONST_INLINE_r12 1113 +#define _LOAD_CONST_INLINE_r23 1114 +#define _LOAD_CONST_INLINE_BORROW_r01 1115 +#define _LOAD_CONST_INLINE_BORROW_r12 1116 +#define _LOAD_CONST_INLINE_BORROW_r23 1117 +#define _LOAD_CONST_UNDER_INLINE_r02 1118 +#define _LOAD_CONST_UNDER_INLINE_r12 1119 +#define _LOAD_CONST_UNDER_INLINE_r23 1120 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1121 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1122 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1123 +#define _LOAD_DEREF_r01 1124 +#define _LOAD_FAST_r01 1125 +#define _LOAD_FAST_r12 1126 +#define _LOAD_FAST_r23 1127 +#define _LOAD_FAST_0_r01 1128 +#define _LOAD_FAST_0_r12 1129 +#define _LOAD_FAST_0_r23 1130 +#define _LOAD_FAST_1_r01 1131 +#define _LOAD_FAST_1_r12 1132 +#define _LOAD_FAST_1_r23 1133 +#define _LOAD_FAST_2_r01 1134 +#define _LOAD_FAST_2_r12 1135 +#define _LOAD_FAST_2_r23 1136 +#define _LOAD_FAST_3_r01 1137 +#define _LOAD_FAST_3_r12 1138 +#define _LOAD_FAST_3_r23 1139 +#define _LOAD_FAST_4_r01 1140 +#define _LOAD_FAST_4_r12 1141 +#define _LOAD_FAST_4_r23 1142 +#define _LOAD_FAST_5_r01 1143 +#define _LOAD_FAST_5_r12 1144 +#define _LOAD_FAST_5_r23 1145 +#define _LOAD_FAST_6_r01 1146 +#define _LOAD_FAST_6_r12 1147 +#define _LOAD_FAST_6_r23 1148 +#define _LOAD_FAST_7_r01 1149 +#define _LOAD_FAST_7_r12 1150 +#define _LOAD_FAST_7_r23 1151 +#define _LOAD_FAST_AND_CLEAR_r01 1152 +#define _LOAD_FAST_AND_CLEAR_r12 1153 +#define _LOAD_FAST_AND_CLEAR_r23 1154 +#define _LOAD_FAST_BORROW_r01 1155 +#define _LOAD_FAST_BORROW_r12 1156 +#define _LOAD_FAST_BORROW_r23 1157 +#define _LOAD_FAST_BORROW_0_r01 1158 +#define _LOAD_FAST_BORROW_0_r12 1159 +#define _LOAD_FAST_BORROW_0_r23 1160 +#define _LOAD_FAST_BORROW_1_r01 1161 +#define _LOAD_FAST_BORROW_1_r12 1162 +#define _LOAD_FAST_BORROW_1_r23 1163 +#define _LOAD_FAST_BORROW_2_r01 1164 +#define _LOAD_FAST_BORROW_2_r12 1165 +#define _LOAD_FAST_BORROW_2_r23 1166 +#define _LOAD_FAST_BORROW_3_r01 1167 +#define _LOAD_FAST_BORROW_3_r12 1168 +#define _LOAD_FAST_BORROW_3_r23 1169 +#define _LOAD_FAST_BORROW_4_r01 1170 +#define _LOAD_FAST_BORROW_4_r12 1171 +#define _LOAD_FAST_BORROW_4_r23 1172 +#define _LOAD_FAST_BORROW_5_r01 1173 +#define _LOAD_FAST_BORROW_5_r12 1174 +#define _LOAD_FAST_BORROW_5_r23 1175 +#define _LOAD_FAST_BORROW_6_r01 1176 +#define _LOAD_FAST_BORROW_6_r12 1177 +#define _LOAD_FAST_BORROW_6_r23 1178 +#define _LOAD_FAST_BORROW_7_r01 1179 +#define _LOAD_FAST_BORROW_7_r12 1180 +#define _LOAD_FAST_BORROW_7_r23 1181 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1182 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1183 +#define _LOAD_FAST_CHECK_r01 1184 +#define _LOAD_FAST_CHECK_r12 1185 +#define _LOAD_FAST_CHECK_r23 1186 +#define _LOAD_FAST_LOAD_FAST_r02 1187 +#define _LOAD_FAST_LOAD_FAST_r13 1188 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1189 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1190 +#define _LOAD_GLOBAL_r00 1191 +#define _LOAD_GLOBAL_BUILTINS_r01 1192 +#define _LOAD_GLOBAL_MODULE_r01 1193 +#define _LOAD_LOCALS_r01 1194 +#define _LOAD_LOCALS_r12 1195 +#define _LOAD_LOCALS_r23 1196 +#define _LOAD_NAME_r01 1197 +#define _LOAD_SMALL_INT_r01 1198 +#define _LOAD_SMALL_INT_r12 1199 +#define _LOAD_SMALL_INT_r23 1200 +#define _LOAD_SMALL_INT_0_r01 1201 +#define _LOAD_SMALL_INT_0_r12 1202 +#define _LOAD_SMALL_INT_0_r23 1203 +#define _LOAD_SMALL_INT_1_r01 1204 +#define _LOAD_SMALL_INT_1_r12 1205 +#define _LOAD_SMALL_INT_1_r23 1206 +#define _LOAD_SMALL_INT_2_r01 1207 +#define _LOAD_SMALL_INT_2_r12 1208 +#define _LOAD_SMALL_INT_2_r23 1209 +#define _LOAD_SMALL_INT_3_r01 1210 +#define _LOAD_SMALL_INT_3_r12 1211 +#define _LOAD_SMALL_INT_3_r23 1212 +#define _LOAD_SPECIAL_r00 1213 +#define _LOAD_SUPER_ATTR_ATTR_r31 1214 +#define _LOAD_SUPER_ATTR_METHOD_r32 1215 +#define _MAKE_CALLARGS_A_TUPLE_r33 1216 +#define _MAKE_CELL_r00 1217 +#define _MAKE_FUNCTION_r11 1218 +#define _MAKE_WARM_r00 1219 +#define _MAKE_WARM_r11 1220 +#define _MAKE_WARM_r22 1221 +#define _MAKE_WARM_r33 1222 +#define _MAP_ADD_r20 1223 +#define _MATCH_CLASS_r31 1224 +#define _MATCH_KEYS_r23 1225 +#define _MATCH_MAPPING_r02 1226 +#define _MATCH_MAPPING_r12 1227 +#define _MATCH_MAPPING_r23 1228 +#define _MATCH_SEQUENCE_r02 1229 +#define _MATCH_SEQUENCE_r12 1230 +#define _MATCH_SEQUENCE_r23 1231 +#define _MAYBE_EXPAND_METHOD_r00 1232 +#define _MAYBE_EXPAND_METHOD_KW_r11 1233 +#define _MONITOR_CALL_r00 1234 +#define _MONITOR_CALL_KW_r11 1235 +#define _MONITOR_JUMP_BACKWARD_r00 1236 +#define _MONITOR_JUMP_BACKWARD_r11 1237 +#define _MONITOR_JUMP_BACKWARD_r22 1238 +#define _MONITOR_JUMP_BACKWARD_r33 1239 +#define _MONITOR_RESUME_r00 1240 +#define _NOP_r00 1241 +#define _NOP_r11 1242 +#define _NOP_r22 1243 +#define _NOP_r33 1244 +#define _POP_CALL_r20 1245 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1246 +#define _POP_CALL_ONE_r30 1247 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1248 +#define _POP_CALL_TWO_r30 1249 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1250 +#define _POP_EXCEPT_r10 1251 +#define _POP_ITER_r20 1252 +#define _POP_JUMP_IF_FALSE_r00 1253 +#define _POP_JUMP_IF_FALSE_r10 1254 +#define _POP_JUMP_IF_FALSE_r21 1255 +#define _POP_JUMP_IF_FALSE_r32 1256 +#define _POP_JUMP_IF_TRUE_r00 1257 +#define _POP_JUMP_IF_TRUE_r10 1258 +#define _POP_JUMP_IF_TRUE_r21 1259 +#define _POP_JUMP_IF_TRUE_r32 1260 +#define _POP_TOP_r10 1261 +#define _POP_TOP_FLOAT_r00 1262 +#define _POP_TOP_FLOAT_r10 1263 +#define _POP_TOP_FLOAT_r21 1264 +#define _POP_TOP_FLOAT_r32 1265 +#define _POP_TOP_INT_r00 1266 +#define _POP_TOP_INT_r10 1267 +#define _POP_TOP_INT_r21 1268 +#define _POP_TOP_INT_r32 1269 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1270 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1271 +#define _POP_TOP_NOP_r00 1272 +#define _POP_TOP_NOP_r10 1273 +#define _POP_TOP_NOP_r21 1274 +#define _POP_TOP_NOP_r32 1275 +#define _POP_TOP_UNICODE_r00 1276 +#define _POP_TOP_UNICODE_r10 1277 +#define _POP_TOP_UNICODE_r21 1278 +#define _POP_TOP_UNICODE_r32 1279 +#define _POP_TWO_r20 1280 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1281 +#define _PUSH_EXC_INFO_r02 1282 +#define _PUSH_EXC_INFO_r12 1283 +#define _PUSH_EXC_INFO_r23 1284 +#define _PUSH_FRAME_r10 1285 +#define _PUSH_NULL_r01 1286 +#define _PUSH_NULL_r12 1287 +#define _PUSH_NULL_r23 1288 +#define _PUSH_NULL_CONDITIONAL_r00 1289 +#define _PY_FRAME_EX_r31 1290 +#define _PY_FRAME_GENERAL_r01 1291 +#define _PY_FRAME_KW_r11 1292 +#define _QUICKEN_RESUME_r00 1293 +#define _QUICKEN_RESUME_r11 1294 +#define _QUICKEN_RESUME_r22 1295 +#define _QUICKEN_RESUME_r33 1296 +#define _REPLACE_WITH_TRUE_r02 1297 +#define _REPLACE_WITH_TRUE_r12 1298 +#define _REPLACE_WITH_TRUE_r23 1299 +#define _RESUME_CHECK_r00 1300 +#define _RESUME_CHECK_r11 1301 +#define _RESUME_CHECK_r22 1302 +#define _RESUME_CHECK_r33 1303 +#define _RETURN_GENERATOR_r01 1304 +#define _RETURN_VALUE_r11 1305 +#define _SAVE_RETURN_OFFSET_r00 1306 +#define _SAVE_RETURN_OFFSET_r11 1307 +#define _SAVE_RETURN_OFFSET_r22 1308 +#define _SAVE_RETURN_OFFSET_r33 1309 +#define _SEND_r22 1310 +#define _SEND_GEN_FRAME_r22 1311 +#define _SETUP_ANNOTATIONS_r00 1312 +#define _SET_ADD_r10 1313 +#define _SET_FUNCTION_ATTRIBUTE_r01 1314 +#define _SET_FUNCTION_ATTRIBUTE_r11 1315 +#define _SET_FUNCTION_ATTRIBUTE_r21 1316 +#define _SET_FUNCTION_ATTRIBUTE_r32 1317 +#define _SET_IP_r00 1318 +#define _SET_IP_r11 1319 +#define _SET_IP_r22 1320 +#define _SET_IP_r33 1321 +#define _SET_UPDATE_r10 1322 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1323 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1324 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1325 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1326 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1327 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1328 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1329 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1330 +#define _SPILL_OR_RELOAD_r01 1331 +#define _SPILL_OR_RELOAD_r02 1332 +#define _SPILL_OR_RELOAD_r03 1333 +#define _SPILL_OR_RELOAD_r10 1334 +#define _SPILL_OR_RELOAD_r12 1335 +#define _SPILL_OR_RELOAD_r13 1336 +#define _SPILL_OR_RELOAD_r20 1337 +#define _SPILL_OR_RELOAD_r21 1338 +#define _SPILL_OR_RELOAD_r23 1339 +#define _SPILL_OR_RELOAD_r30 1340 +#define _SPILL_OR_RELOAD_r31 1341 +#define _SPILL_OR_RELOAD_r32 1342 +#define _START_EXECUTOR_r00 1343 +#define _STORE_ATTR_r20 1344 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1345 +#define _STORE_ATTR_SLOT_r21 1346 +#define _STORE_ATTR_WITH_HINT_r21 1347 +#define _STORE_DEREF_r10 1348 +#define _STORE_FAST_LOAD_FAST_r11 1349 +#define _STORE_FAST_STORE_FAST_r20 1350 +#define _STORE_GLOBAL_r10 1351 +#define _STORE_NAME_r10 1352 +#define _STORE_SLICE_r30 1353 +#define _STORE_SUBSCR_r30 1354 +#define _STORE_SUBSCR_DICT_r31 1355 +#define _STORE_SUBSCR_LIST_INT_r32 1356 +#define _SWAP_r11 1357 +#define _SWAP_2_r02 1358 +#define _SWAP_2_r12 1359 +#define _SWAP_2_r22 1360 +#define _SWAP_2_r33 1361 +#define _SWAP_3_r03 1362 +#define _SWAP_3_r13 1363 +#define _SWAP_3_r23 1364 +#define _SWAP_3_r33 1365 +#define _SWAP_FAST_r01 1366 +#define _SWAP_FAST_r11 1367 +#define _SWAP_FAST_r22 1368 +#define _SWAP_FAST_r33 1369 +#define _SWAP_FAST_0_r01 1370 +#define _SWAP_FAST_0_r11 1371 +#define _SWAP_FAST_0_r22 1372 +#define _SWAP_FAST_0_r33 1373 +#define _SWAP_FAST_1_r01 1374 +#define _SWAP_FAST_1_r11 1375 +#define _SWAP_FAST_1_r22 1376 +#define _SWAP_FAST_1_r33 1377 +#define _SWAP_FAST_2_r01 1378 +#define _SWAP_FAST_2_r11 1379 +#define _SWAP_FAST_2_r22 1380 +#define _SWAP_FAST_2_r33 1381 +#define _SWAP_FAST_3_r01 1382 +#define _SWAP_FAST_3_r11 1383 +#define _SWAP_FAST_3_r22 1384 +#define _SWAP_FAST_3_r33 1385 +#define _SWAP_FAST_4_r01 1386 +#define _SWAP_FAST_4_r11 1387 +#define _SWAP_FAST_4_r22 1388 +#define _SWAP_FAST_4_r33 1389 +#define _SWAP_FAST_5_r01 1390 +#define _SWAP_FAST_5_r11 1391 +#define _SWAP_FAST_5_r22 1392 +#define _SWAP_FAST_5_r33 1393 +#define _SWAP_FAST_6_r01 1394 +#define _SWAP_FAST_6_r11 1395 +#define _SWAP_FAST_6_r22 1396 +#define _SWAP_FAST_6_r33 1397 +#define _SWAP_FAST_7_r01 1398 +#define _SWAP_FAST_7_r11 1399 +#define _SWAP_FAST_7_r22 1400 +#define _SWAP_FAST_7_r33 1401 +#define _TIER2_RESUME_CHECK_r00 1402 +#define _TIER2_RESUME_CHECK_r11 1403 +#define _TIER2_RESUME_CHECK_r22 1404 +#define _TIER2_RESUME_CHECK_r33 1405 +#define _TO_BOOL_r11 1406 +#define _TO_BOOL_BOOL_r01 1407 +#define _TO_BOOL_BOOL_r11 1408 +#define _TO_BOOL_BOOL_r22 1409 +#define _TO_BOOL_BOOL_r33 1410 +#define _TO_BOOL_INT_r02 1411 +#define _TO_BOOL_INT_r12 1412 +#define _TO_BOOL_INT_r23 1413 +#define _TO_BOOL_LIST_r02 1414 +#define _TO_BOOL_LIST_r12 1415 +#define _TO_BOOL_LIST_r23 1416 +#define _TO_BOOL_NONE_r01 1417 +#define _TO_BOOL_NONE_r11 1418 +#define _TO_BOOL_NONE_r22 1419 +#define _TO_BOOL_NONE_r33 1420 +#define _TO_BOOL_STR_r02 1421 +#define _TO_BOOL_STR_r12 1422 +#define _TO_BOOL_STR_r23 1423 +#define _TRACE_RECORD_r00 1424 +#define _UNARY_INVERT_r12 1425 +#define _UNARY_NEGATIVE_r12 1426 +#define _UNARY_NOT_r01 1427 +#define _UNARY_NOT_r11 1428 +#define _UNARY_NOT_r22 1429 +#define _UNARY_NOT_r33 1430 +#define _UNPACK_EX_r10 1431 +#define _UNPACK_SEQUENCE_r10 1432 +#define _UNPACK_SEQUENCE_LIST_r10 1433 +#define _UNPACK_SEQUENCE_TUPLE_r10 1434 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1435 +#define _WITH_EXCEPT_START_r33 1436 +#define _YIELD_VALUE_r11 1437 +#define MAX_UOP_REGS_ID 1437 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index f9f22ba0481..07c4f0aeb4a 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -193,7 +193,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_TYPE_VERSION_AND_LOCK] = HAS_EXIT_FLAG, [_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG, [_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG, - [_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG, [_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG, [_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG, [_CHECK_ATTR_CLASS] = HAS_EXIT_FLAG, @@ -352,6 +352,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, + [_INSERT_1_LOAD_CONST_INLINE] = 0, [_INSERT_1_LOAD_CONST_INLINE_BORROW] = 0, [_INSERT_2_LOAD_CONST_INLINE_BORROW] = 0, [_SHUFFLE_2_LOAD_CONST_INLINE_BORROW] = 0, @@ -1814,7 +1815,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { .best = { 1, 1, 1, 1 }, .entries = { { -1, -1, -1 }, - { 1, 1, _LOAD_ATTR_MODULE_r11 }, + { 2, 1, _LOAD_ATTR_MODULE_r12 }, { -1, -1, -1 }, { -1, -1, -1 }, }, @@ -3241,6 +3242,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { 1, 3, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 }, }, }, + [_INSERT_1_LOAD_CONST_INLINE] = { + .best = { 0, 1, 2, 2 }, + .entries = { + { 2, 0, _INSERT_1_LOAD_CONST_INLINE_r02 }, + { 2, 1, _INSERT_1_LOAD_CONST_INLINE_r12 }, + { 3, 2, _INSERT_1_LOAD_CONST_INLINE_r23 }, + { -1, -1, -1 }, + }, + }, [_INSERT_1_LOAD_CONST_INLINE_BORROW] = { .best = { 0, 1, 2, 2 }, .entries = { @@ -3789,7 +3799,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_LOAD_ATTR_INSTANCE_VALUE_r02] = _LOAD_ATTR_INSTANCE_VALUE, [_LOAD_ATTR_INSTANCE_VALUE_r12] = _LOAD_ATTR_INSTANCE_VALUE, [_LOAD_ATTR_INSTANCE_VALUE_r23] = _LOAD_ATTR_INSTANCE_VALUE, - [_LOAD_ATTR_MODULE_r11] = _LOAD_ATTR_MODULE, + [_LOAD_ATTR_MODULE_r12] = _LOAD_ATTR_MODULE, [_LOAD_ATTR_WITH_HINT_r12] = _LOAD_ATTR_WITH_HINT, [_LOAD_ATTR_SLOT_r02] = _LOAD_ATTR_SLOT, [_LOAD_ATTR_SLOT_r12] = _LOAD_ATTR_SLOT, @@ -4133,6 +4143,9 @@ 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, + [_INSERT_1_LOAD_CONST_INLINE_r02] = _INSERT_1_LOAD_CONST_INLINE, + [_INSERT_1_LOAD_CONST_INLINE_r12] = _INSERT_1_LOAD_CONST_INLINE, + [_INSERT_1_LOAD_CONST_INLINE_r23] = _INSERT_1_LOAD_CONST_INLINE, [_INSERT_1_LOAD_CONST_INLINE_BORROW_r02] = _INSERT_1_LOAD_CONST_INLINE_BORROW, [_INSERT_1_LOAD_CONST_INLINE_BORROW_r12] = _INSERT_1_LOAD_CONST_INLINE_BORROW, [_INSERT_1_LOAD_CONST_INLINE_BORROW_r23] = _INSERT_1_LOAD_CONST_INLINE_BORROW, @@ -4825,6 +4838,10 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_INIT_CALL_PY_EXACT_ARGS_3_r01] = "_INIT_CALL_PY_EXACT_ARGS_3_r01", [_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4", [_INIT_CALL_PY_EXACT_ARGS_4_r01] = "_INIT_CALL_PY_EXACT_ARGS_4_r01", + [_INSERT_1_LOAD_CONST_INLINE] = "_INSERT_1_LOAD_CONST_INLINE", + [_INSERT_1_LOAD_CONST_INLINE_r02] = "_INSERT_1_LOAD_CONST_INLINE_r02", + [_INSERT_1_LOAD_CONST_INLINE_r12] = "_INSERT_1_LOAD_CONST_INLINE_r12", + [_INSERT_1_LOAD_CONST_INLINE_r23] = "_INSERT_1_LOAD_CONST_INLINE_r23", [_INSERT_1_LOAD_CONST_INLINE_BORROW] = "_INSERT_1_LOAD_CONST_INLINE_BORROW", [_INSERT_1_LOAD_CONST_INLINE_BORROW_r02] = "_INSERT_1_LOAD_CONST_INLINE_BORROW_r02", [_INSERT_1_LOAD_CONST_INLINE_BORROW_r12] = "_INSERT_1_LOAD_CONST_INLINE_BORROW_r12", @@ -4893,7 +4910,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_LOAD_ATTR_METHOD_WITH_VALUES_r12] = "_LOAD_ATTR_METHOD_WITH_VALUES_r12", [_LOAD_ATTR_METHOD_WITH_VALUES_r23] = "_LOAD_ATTR_METHOD_WITH_VALUES_r23", [_LOAD_ATTR_MODULE] = "_LOAD_ATTR_MODULE", - [_LOAD_ATTR_MODULE_r11] = "_LOAD_ATTR_MODULE_r11", + [_LOAD_ATTR_MODULE_r12] = "_LOAD_ATTR_MODULE_r12", [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT", [_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11", [_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", @@ -5982,6 +5999,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 2; case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW: return 3; + case _INSERT_1_LOAD_CONST_INLINE: + return 1; case _INSERT_1_LOAD_CONST_INLINE_BORROW: return 1; case _INSERT_2_LOAD_CONST_INLINE_BORROW: diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 0a02f29d978..7808700f6a2 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2898,6 +2898,23 @@ class C(): self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) self.assertIn("_POP_TOP_NOP", uops) + def test_load_attr_module(self): + def testfunc(n): + import math + x = 0 + for _ in range(n): + y = math.pi + if y: + 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(("_LOAD_ATTR_MODULE", "_POP_TOP_NOP"), itertools.pairwise(uops)) + self.assertLessEqual(count_ops(ex, "_POP_TOP"), 2) + def test_load_attr_with_hint(self): def testfunc(n): class C: diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index 3c9eb919436..d46af254a41 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -8398,6 +8398,8 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); _PyStackRef owner; _PyStackRef attr; + _PyStackRef o; + _PyStackRef value; _PyStackRef *null; /* Skip 1 cache entry */ // _LOAD_ATTR_MODULE @@ -8441,9 +8443,14 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); + o = owner; + } + // _POP_TOP + { + value = o; stack_pointer[-1] = attr; _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } /* Skip 5 cache entries */ diff --git a/Python/bytecodes.c b/Python/bytecodes.c index bec03119993..edda90b5fb3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2452,7 +2452,7 @@ dummy_func( unused/5 + _PUSH_NULL_CONDITIONAL; - op(_LOAD_ATTR_MODULE, (dict_version/2, index/1, owner -- attr)) { + op(_LOAD_ATTR_MODULE, (dict_version/2, index/1, owner -- attr, o)) { PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro); PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict; @@ -2473,12 +2473,14 @@ dummy_func( attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); - PyStackRef_CLOSE(owner); + o = owner; + DEAD(owner); } macro(LOAD_ATTR_MODULE) = unused/1 + _LOAD_ATTR_MODULE + + POP_TOP + unused/5 + _PUSH_NULL_CONDITIONAL; @@ -5444,6 +5446,12 @@ dummy_func( value = PyStackRef_FromPyObjectBorrow(ptr); } + tier2 op(_INSERT_1_LOAD_CONST_INLINE, (ptr/4, left -- res, l)) { + res = PyStackRef_FromPyObjectNew(ptr); + l = left; + INPUTS_DEAD(); + } + tier2 op(_INSERT_1_LOAD_CONST_INLINE_BORROW, (ptr/4, left -- res, l)) { res = PyStackRef_FromPyObjectBorrow(ptr); l = left; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index f51466abea9..8901c259525 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9169,11 +9169,12 @@ break; } - case _LOAD_ATTR_MODULE_r11: { + case _LOAD_ATTR_MODULE_r12: { CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef owner; _PyStackRef attr; + _PyStackRef o; _PyStackRef _stack_item_0 = _tos_cache0; owner = _stack_item_0; uint32_t dict_version = (uint32_t)CURRENT_OPERAND0_32(); @@ -9218,18 +9219,11 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); - stack_pointer[0] = attr; - stack_pointer += 1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); - stack_pointer = _PyFrame_GetStackPointer(frame); + o = owner; + _tos_cache1 = o; _tos_cache0 = attr; - _tos_cache1 = PyStackRef_ZERO_BITS; _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + SET_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -19078,6 +19072,63 @@ break; } + case _INSERT_1_LOAD_CONST_INLINE_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + left = stack_pointer[-1]; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectNew(ptr); + l = left; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _INSERT_1_LOAD_CONST_INLINE_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef _stack_item_0 = _tos_cache0; + left = _stack_item_0; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectNew(ptr); + l = left; + _tos_cache1 = l; + _tos_cache0 = res; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _INSERT_1_LOAD_CONST_INLINE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef left; + _PyStackRef res; + _PyStackRef l; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + left = _stack_item_1; + PyObject *ptr = (PyObject *)CURRENT_OPERAND0_64(); + res = PyStackRef_FromPyObjectNew(ptr); + l = left; + _tos_cache2 = l; + _tos_cache1 = res; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _INSERT_1_LOAD_CONST_INLINE_BORROW_r02: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index ae9e1e5421b..16349766d62 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -8397,6 +8397,8 @@ static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size"); _PyStackRef owner; _PyStackRef attr; + _PyStackRef o; + _PyStackRef value; _PyStackRef *null; /* Skip 1 cache entry */ // _LOAD_ATTR_MODULE @@ -8440,9 +8442,14 @@ attr = PyStackRef_FromPyObjectNew(attr_o); #endif STAT_INC(LOAD_ATTR, hit); + o = owner; + } + // _POP_TOP + { + value = o; stack_pointer[-1] = attr; _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(owner); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); } /* Skip 5 cache entries */ diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 65c9239f1ff..35d72e851af 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -128,7 +128,7 @@ type_watcher_callback(PyTypeObject* type) } static PyObject * -convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop) +convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop, bool insert) { assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS || inst->opcode == _LOAD_ATTR_MODULE); assert(PyDict_CheckExact(obj)); @@ -148,15 +148,22 @@ convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop) if (res == NULL) { return NULL; } - if (_Py_IsImmortal(res)) { - inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE_BORROW; - } - else { - inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE : _LOAD_CONST_INLINE; - } - if (inst->oparg & 1) { - assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL); - assert(inst[1].oparg & 1); + if (insert) { + if (_Py_IsImmortal(res)) { + inst->opcode = _INSERT_1_LOAD_CONST_INLINE_BORROW; + } else { + inst->opcode = _INSERT_1_LOAD_CONST_INLINE; + } + } else { + if (_Py_IsImmortal(res)) { + inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE_BORROW; + } else { + inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE : _LOAD_CONST_INLINE; + } + if (inst->oparg & 1) { + assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL); + assert(inst[1].oparg & 1); + } } inst->operand0 = (uint64_t)res; return res; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 9bc6075adc7..5a3480ab316 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -694,7 +694,7 @@ dummy_func(void) { o = owner; } - op(_LOAD_ATTR_MODULE, (dict_version/2, index/1, owner -- attr)) { + op(_LOAD_ATTR_MODULE, (dict_version/2, index/1, owner -- attr, o)) { (void)dict_version; (void)index; attr = PyJitRef_NULL; @@ -706,7 +706,7 @@ dummy_func(void) { if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { PyDict_Watch(GLOBALS_WATCHER_ID, dict); _Py_BloomFilter_Add(dependencies, dict); - PyObject *res = convert_global_to_const(this_instr, dict, true); + PyObject *res = convert_global_to_const(this_instr, dict, false, true); if (res == NULL) { attr = sym_new_not_null(ctx); } @@ -721,6 +721,7 @@ dummy_func(void) { /* No conversion made. We don't know what `attr` is. */ attr = sym_new_not_null(ctx); } + o = owner; } op (_PUSH_NULL_CONDITIONAL, ( -- null[oparg & 1])) { @@ -1585,7 +1586,7 @@ dummy_func(void) { ctx->builtins_watched = true; } if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { - cnst = convert_global_to_const(this_instr, builtins, false); + cnst = convert_global_to_const(this_instr, builtins, false, false); } } if (cnst == NULL) { @@ -1624,7 +1625,7 @@ dummy_func(void) { ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { - cnst = convert_global_to_const(this_instr, globals, false); + cnst = convert_global_to_const(this_instr, globals, false, false); } } } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2cd1f833dc3..9dc1da3c93b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1572,7 +1572,7 @@ ctx->frame->globals_checked_version = version; } if (ctx->frame->globals_checked_version == version) { - cnst = convert_global_to_const(this_instr, globals, false); + cnst = convert_global_to_const(this_instr, globals, false, false); } } } @@ -1615,7 +1615,7 @@ ctx->builtins_watched = true; } if (ctx->frame->globals_checked_version != 0 && ctx->frame->globals_watched) { - cnst = convert_global_to_const(this_instr, builtins, false); + cnst = convert_global_to_const(this_instr, builtins, false, false); } } if (cnst == NULL) { @@ -1875,6 +1875,7 @@ case _LOAD_ATTR_MODULE: { JitOptRef owner; JitOptRef attr; + JitOptRef o; owner = stack_pointer[-1]; uint32_t dict_version = (uint32_t)this_instr->operand0; uint16_t index = (uint16_t)this_instr->operand0; @@ -1890,7 +1891,7 @@ if (watched_mutations < _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) { PyDict_Watch(GLOBALS_WATCHER_ID, dict); _Py_BloomFilter_Add(dependencies, dict); - PyObject *res = convert_global_to_const(this_instr, dict, true); + PyObject *res = convert_global_to_const(this_instr, dict, false, true); if (res == NULL) { attr = sym_new_not_null(ctx); } @@ -1903,7 +1904,12 @@ if (PyJitRef_IsNull(attr)) { attr = sym_new_not_null(ctx); } + o = owner; + CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; + stack_pointer[0] = o; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -4005,6 +4011,19 @@ break; } + case _INSERT_1_LOAD_CONST_INLINE: { + JitOptRef res; + JitOptRef l; + res = sym_new_not_null(ctx); + l = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); + stack_pointer[-1] = res; + stack_pointer[0] = l; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + case _INSERT_1_LOAD_CONST_INLINE_BORROW: { JitOptRef res; JitOptRef l; From 76d3ae71bab2f6391193610f4aedf8337be4112a Mon Sep 17 00:00:00 2001 From: benediktjohannes Date: Sun, 25 Jan 2026 23:22:43 +0100 Subject: [PATCH 074/133] gh-144217: Add dicom support (medical imaging) to mimetypes (GH-144218) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Peter Bierma --- Doc/whatsnew/3.15.rst | 1 + Lib/mimetypes.py | 1 + Lib/test/test_mimetypes.py | 1 + .../next/Library/2026-01-25-03-23-20.gh-issue-144217.E1wVXH.rst | 1 + 4 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-25-03-23-20.gh-issue-144217.E1wVXH.rst diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 8c3223d9a78..c412f48606c 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -603,6 +603,7 @@ math mimetypes --------- +* Add ``application/dicom`` MIME type for ``.dcm`` extension. (Contributed by Benedikt Johannes in :gh:`144217`.) * Add ``application/node`` MIME type for ``.cjs`` extension. (Contributed by John Franey in :gh:`140937`.) * Add ``application/toml``. (Contributed by Gil Forcada in :gh:`139959`.) * Rename ``application/x-texinfo`` to ``application/texinfo``. diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index 07ac079186f..361f924b55d 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -477,6 +477,7 @@ def _default_mime_types(): types_map = _types_map_default = { '.js' : 'text/javascript', '.mjs' : 'text/javascript', + '.dcm' : 'application/dicom', '.epub' : 'application/epub+zip', '.gz' : 'application/gzip', '.json' : 'application/json', diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 0f29640bc1c..32adc593591 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -226,6 +226,7 @@ def check_extensions(): for mime_type, ext in ( ("application/epub+zip", ".epub"), ("application/octet-stream", ".bin"), + ("application/dicom", ".dcm"), ("application/gzip", ".gz"), ("application/ogg", ".ogx"), ("application/pdf", ".pdf"), diff --git a/Misc/NEWS.d/next/Library/2026-01-25-03-23-20.gh-issue-144217.E1wVXH.rst b/Misc/NEWS.d/next/Library/2026-01-25-03-23-20.gh-issue-144217.E1wVXH.rst new file mode 100644 index 00000000000..d85df59b374 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-25-03-23-20.gh-issue-144217.E1wVXH.rst @@ -0,0 +1 @@ +:mod:`mimetypes`: Add support for DICOM files (for medical imaging) with the official MIME type ``application/dicom``. Patch by Benedikt Johannes. From 639c1ad4f1ef5c2409a62fa8ed16e6aa3a6f9ab8 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 25 Jan 2026 17:28:58 -0800 Subject: [PATCH 075/133] gh-144169: Fix three crashes in AST objects with non-str kwargs (#144178) Co-authored-by: Victor Stinner --- Lib/test/test_ast/test_ast.py | 28 +++++++++++++++++++ ...-01-23-06-43-21.gh-issue-144169.LFy9yi.rst | 2 ++ Parser/asdl_c.py | 6 ++-- Python/Python-ast.c | 6 ++-- 4 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-23-06-43-21.gh-issue-144169.LFy9yi.rst diff --git a/Lib/test/test_ast/test_ast.py b/Lib/test/test_ast/test_ast.py index 3917407fb37..c5f42cb7888 100644 --- a/Lib/test/test_ast/test_ast.py +++ b/Lib/test/test_ast/test_ast.py @@ -1443,6 +1443,13 @@ def test_replace_reject_unknown_instance_fields(self): self.assertIs(node.ctx, context) self.assertRaises(AttributeError, getattr, node, 'unknown') + def test_replace_non_str_kwarg(self): + node = ast.Name(id="x") + errmsg = "got an unexpected keyword argument tp_name, key); res = -1; goto cleanup; @@ -965,7 +965,7 @@ def visitModule(self, mod): else if (contains == 0) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ got an unexpected keyword argument '%U'. " + "%.400s.__init__ got an unexpected keyword argument %R. " "Support for arbitrary keyword arguments is deprecated " "and will be removed in Python 3.15.", Py_TYPE(self)->tp_name, key @@ -1207,7 +1207,7 @@ def visitModule(self, mod): if (rc == 0) { PyErr_Format(PyExc_TypeError, "%.400s.__replace__ got an unexpected keyword " - "argument '%U'.", Py_TYPE(self)->tp_name, key); + "argument %R.", Py_TYPE(self)->tp_name, key); Py_DECREF(expecting); return -1; } diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 79608dee9bf..1cc88dc179e 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -5226,7 +5226,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) } if (p == 0) { PyErr_Format(PyExc_TypeError, - "%.400s got multiple values for argument '%U'", + "%.400s got multiple values for argument %R", Py_TYPE(self)->tp_name, key); res = -1; goto cleanup; @@ -5249,7 +5249,7 @@ ast_type_init(PyObject *self, PyObject *args, PyObject *kw) else if (contains == 0) { if (PyErr_WarnFormat( PyExc_DeprecationWarning, 1, - "%.400s.__init__ got an unexpected keyword argument '%U'. " + "%.400s.__init__ got an unexpected keyword argument %R. " "Support for arbitrary keyword arguments is deprecated " "and will be removed in Python 3.15.", Py_TYPE(self)->tp_name, key @@ -5491,7 +5491,7 @@ ast_type_replace_check(PyObject *self, if (rc == 0) { PyErr_Format(PyExc_TypeError, "%.400s.__replace__ got an unexpected keyword " - "argument '%U'.", Py_TYPE(self)->tp_name, key); + "argument %R.", Py_TYPE(self)->tp_name, key); Py_DECREF(expecting); return -1; } From 99821474336187eaf657740c4eb618044d83b9c7 Mon Sep 17 00:00:00 2001 From: Solomon Ritzow <11698787+ritzow@users.noreply.github.com> Date: Mon, 26 Jan 2026 00:07:56 -0800 Subject: [PATCH 076/133] gh-144233: Fix typo in os.eventfd documentation (#144234) --- Doc/library/os.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 31c0964cda0..dad54c0e82b 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -4262,7 +4262,7 @@ features: import os # semaphore with start value '1' - fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFC_CLOEXEC) + fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFD_CLOEXEC) try: # acquire semaphore v = os.eventfd_read(fd) From decb25e8f0051cafcbe7d38171371cf47185165b Mon Sep 17 00:00:00 2001 From: Priyanshu Singh Date: Mon, 26 Jan 2026 17:43:49 +0530 Subject: [PATCH 077/133] gh-144128: Fix crash in array.fromlist with reentrant __index__ (#144138) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Peter Bierma Co-authored-by: Victor Stinner --- Lib/test/test_array.py | 17 +++++++++++++++ ...-01-22-10-18-17.gh-issue-144128.akwY06.rst | 2 ++ Modules/arraymodule.c | 21 +++++++++++++------ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-22-10-18-17.gh-issue-144128.akwY06.rst diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 83b3c978da3..b49df029f03 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -67,6 +67,23 @@ def test_empty(self): a += a self.assertEqual(len(a), 0) + def test_fromlist_reentrant_index_mutation(self): + + class Evil: + def __init__(self, lst): + self.lst = lst + def __index__(self): + self.lst.clear() + return "not an int" + + for typecode in ('I', 'L', 'Q'): + with self.subTest(typecode=typecode): + lst = [] + lst.append(Evil(lst)) + a = array.array(typecode) + with self.assertRaises(TypeError): + a.fromlist(lst) + # Machine format codes. # diff --git a/Misc/NEWS.d/next/Library/2026-01-22-10-18-17.gh-issue-144128.akwY06.rst b/Misc/NEWS.d/next/Library/2026-01-22-10-18-17.gh-issue-144128.akwY06.rst new file mode 100644 index 00000000000..4010695aec9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-22-10-18-17.gh-issue-144128.akwY06.rst @@ -0,0 +1,2 @@ +Fix a crash in :meth:`array.array.fromlist` when an element's :meth:`~object.__index__` method mutates +the input list during conversion. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 729e085c19f..5769a796b18 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -408,10 +408,13 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) int do_decref = 0; /* if nb_int was called */ if (!PyLong_Check(v)) { - v = _PyNumber_Index(v); - if (NULL == v) { + Py_INCREF(v); + PyObject *res = _PyNumber_Index(v); + Py_DECREF(v); + if (NULL == res) { return -1; } + v = res; do_decref = 1; } x = PyLong_AsUnsignedLong(v); @@ -468,10 +471,13 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) int do_decref = 0; /* if nb_int was called */ if (!PyLong_Check(v)) { - v = _PyNumber_Index(v); - if (NULL == v) { + Py_INCREF(v); + PyObject *res = _PyNumber_Index(v); + Py_DECREF(v); + if (NULL == res) { return -1; } + v = res; do_decref = 1; } x = PyLong_AsUnsignedLong(v); @@ -521,10 +527,13 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) int do_decref = 0; /* if nb_int was called */ if (!PyLong_Check(v)) { - v = _PyNumber_Index(v); - if (NULL == v) { + Py_INCREF(v); + PyObject *res = _PyNumber_Index(v); + Py_DECREF(v); + if (NULL == res) { return -1; } + v = res; do_decref = 1; } x = PyLong_AsUnsignedLongLong(v); From 8f459255eba2b6639f1912e5c5e318a7cdafada1 Mon Sep 17 00:00:00 2001 From: VanshAgarwal24036 <148854295+VanshAgarwal24036@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:57:42 +0530 Subject: [PATCH 078/133] gh-144100: Fix crash for POINTER(str) used in ctypes argtypes (#144108) Co-authored-by: Victor Stinner --- Lib/test/test_ctypes/test_pointers.py | 10 ++++++++++ .../2026-01-21-19-39-07.gh-issue-144100.hLMZ8Y.rst | 3 +++ Modules/_ctypes/_ctypes.c | 8 +++++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-21-19-39-07.gh-issue-144100.hLMZ8Y.rst diff --git a/Lib/test/test_ctypes/test_pointers.py b/Lib/test/test_ctypes/test_pointers.py index a8d243a45de..771cc8fbe0e 100644 --- a/Lib/test/test_ctypes/test_pointers.py +++ b/Lib/test/test_ctypes/test_pointers.py @@ -403,6 +403,16 @@ class Cls(Structure): self.assertEqual(len(ws_typ), 0, ws_typ) self.assertEqual(len(ws_ptr), 0, ws_ptr) + def test_pointer_proto_missing_argtypes_error(self): + class BadType(ctypes._Pointer): + # _type_ is intentionally missing + pass + + func = ctypes.pythonapi.Py_GetVersion + func.argtypes = (BadType,) + + with self.assertRaises(ctypes.ArgumentError): + func(object()) class PointerTypeCacheTestCase(unittest.TestCase): # dummy tests to check warnings and base behavior diff --git a/Misc/NEWS.d/next/Library/2026-01-21-19-39-07.gh-issue-144100.hLMZ8Y.rst b/Misc/NEWS.d/next/Library/2026-01-21-19-39-07.gh-issue-144100.hLMZ8Y.rst new file mode 100644 index 00000000000..7093b753141 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-21-19-39-07.gh-issue-144100.hLMZ8Y.rst @@ -0,0 +1,3 @@ +Fixed a crash in ctypes when using a deprecated ``POINTER(str)`` type in +``argtypes``. Instead of aborting, ctypes now raises a proper Python +exception when the pointer target type is unresolved. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 563e95a7625..6d9193af657 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1419,7 +1419,13 @@ PyCPointerType_from_param_impl(PyObject *type, PyTypeObject *cls, /* If we expect POINTER(), but receive a instance, accept it by calling byref(). */ - assert(typeinfo->proto); + if (typeinfo->proto == NULL) { + PyErr_SetString( + PyExc_TypeError, + "cannot convert argument: POINTER _type_ type is not set" + ); + return NULL; + } switch (PyObject_IsInstance(value, typeinfo->proto)) { case 1: Py_INCREF(value); /* _byref steals a refcount */ From 923d9d2ac23b583a7fb66e2867d8dcc07fec9a40 Mon Sep 17 00:00:00 2001 From: Yashraj Date: Mon, 26 Jan 2026 19:08:23 +0530 Subject: [PATCH 079/133] gh-143928: Remove outdated comparison between pickle and marshal regarding recursion (#144025) --- Doc/library/pickle.rst | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Doc/library/pickle.rst b/Doc/library/pickle.rst index 3a9b66ec7e7..7b0d979d61a 100644 --- a/Doc/library/pickle.rst +++ b/Doc/library/pickle.rst @@ -56,19 +56,6 @@ files. The :mod:`pickle` module differs from :mod:`marshal` in several significant ways: -* The :mod:`pickle` module keeps track of the objects it has already serialized, - so that later references to the same object won't be serialized again. - :mod:`marshal` doesn't do this. - - This has implications both for recursive objects and object sharing. Recursive - objects are objects that contain references to themselves. These are not - handled by marshal, and in fact, attempting to marshal recursive objects will - crash your Python interpreter. Object sharing happens when there are multiple - references to the same object in different places in the object hierarchy being - serialized. :mod:`pickle` stores such objects only once, and ensures that all - other references point to the master copy. Shared objects remain shared, which - can be very important for mutable objects. - * :mod:`marshal` cannot be used to serialize user-defined classes and their instances. :mod:`pickle` can save and restore class instances transparently, however the class definition must be importable and live in the same module as From 1f55caf97e0906f2b8b693b01d3d6073df8187c1 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Mon, 26 Jan 2026 22:26:55 +0800 Subject: [PATCH 080/133] gh-144212: Add `image/jxl` to `mimetypes` (GH-144213) --- Doc/whatsnew/3.15.rst | 1 + Lib/mimetypes.py | 1 + Lib/test/test_mimetypes.py | 1 + .../next/Library/2026-01-24-23-11-17.gh-issue-144212.IXqVL8.rst | 1 + 4 files changed, 4 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-24-23-11-17.gh-issue-144212.IXqVL8.rst diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index c412f48606c..aec6b1ceea3 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -606,6 +606,7 @@ mimetypes * Add ``application/dicom`` MIME type for ``.dcm`` extension. (Contributed by Benedikt Johannes in :gh:`144217`.) * Add ``application/node`` MIME type for ``.cjs`` extension. (Contributed by John Franey in :gh:`140937`.) * Add ``application/toml``. (Contributed by Gil Forcada in :gh:`139959`.) +* Add ``image/jxl``. (Contributed by Foolbar in :gh:`144213`.) * Rename ``application/x-texinfo`` to ``application/texinfo``. (Contributed by Charlie Lin in :gh:`140165`.) * Changed the MIME type for ``.ai`` files to ``application/pdf``. diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index 361f924b55d..fc916c470a0 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -609,6 +609,7 @@ def _default_mime_types(): '.jpeg' : 'image/jpeg', '.jpm' : 'image/jpm', '.jpx' : 'image/jpx', + '.jxl' : 'image/jxl', '.heic' : 'image/heic', '.heif' : 'image/heif', '.png' : 'image/png', diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 32adc593591..fe7584f1f9d 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -271,6 +271,7 @@ def check_extensions(): ("image/jp2", ".jp2"), ("image/jpeg", ".jpg"), ("image/jpm", ".jpm"), + ("image/jxl", ".jxl"), ("image/t38", ".t38"), ("image/tiff", ".tiff"), ("image/tiff-fx", ".tfx"), diff --git a/Misc/NEWS.d/next/Library/2026-01-24-23-11-17.gh-issue-144212.IXqVL8.rst b/Misc/NEWS.d/next/Library/2026-01-24-23-11-17.gh-issue-144212.IXqVL8.rst new file mode 100644 index 00000000000..be77fb345ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-24-23-11-17.gh-issue-144212.IXqVL8.rst @@ -0,0 +1 @@ +Mime type ``image/jxl`` is now supported by :mod:`mimetypes`. From 19de10d3d8605a290492e4fb3871e12638b0f7bb Mon Sep 17 00:00:00 2001 From: Jake Lishman Date: Mon, 26 Jan 2026 15:45:17 +0000 Subject: [PATCH 081/133] gh-140557: Force alignment of empty `bytearray` and `array.array` buffers (GH-140559) This ensures the buffers used by the empty `bytearray` and `array.array` are aligned the same as a pointer returned by the allocator. This is a more convenient default for interop with other languages that have stricter requirements of type-safe buffers (e.g. Rust's `&[T]` type) even when empty. --- Lib/test/test_buffer.py | 35 +++++++++++++++++++ Misc/ACKS | 1 + ...-10-24-17-30-51.gh-issue-140557.X2GETk.rst | 2 ++ ...-01-07-11-57-59.gh-issue-140557.3P6-nW.rst | 2 ++ Modules/_testcapi/buffer.c | 24 +++++++++++++ Modules/arraymodule.c | 2 +- 6 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-10-24-17-30-51.gh-issue-140557.X2GETk.rst create mode 100644 Misc/NEWS.d/next/Library/2026-01-07-11-57-59.gh-issue-140557.3P6-nW.rst diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 19582e75716..ab65a44bda6 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -4447,6 +4447,41 @@ def test_bytearray_release_buffer_read_flag(self): with self.assertRaises(SystemError): obj.__buffer__(inspect.BufferFlags.WRITE) + @support.cpython_only + @unittest.skipIf(_testcapi is None, "requires _testcapi") + def test_bytearray_alignment(self): + # gh-140557: pointer alignment of buffers including empty allocation + # should be at least to `size_t`. + align = struct.calcsize("N") + cases = [ + bytearray(), + bytearray(1), + bytearray(b"0123456789abcdef"), + bytearray(16), + ] + ptrs = [_testcapi.buffer_pointer_as_int(array) for array in cases] + self.assertEqual([ptr % align for ptr in ptrs], [0]*len(ptrs)) + + @support.cpython_only + @unittest.skipIf(_testcapi is None, "requires _testcapi") + def test_array_alignment(self): + # gh-140557: pointer alignment of buffers including empty allocation + # should match the maximum array alignment. + align = max(struct.calcsize(fmt) for fmt in ARRAY) + cases = [array.array(fmt) for fmt in ARRAY] + # Empty arrays + self.assertEqual( + [_testcapi.buffer_pointer_as_int(case) % align for case in cases], + [0] * len(cases), + ) + for case in cases: + case.append(0) + # Allocated arrays + self.assertEqual( + [_testcapi.buffer_pointer_as_int(case) % align for case in cases], + [0] * len(cases), + ) + @support.cpython_only def test_pybuffer_size_from_format(self): # basic tests diff --git a/Misc/ACKS b/Misc/ACKS index feb16a62792..3fe9dcfcc9e 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1151,6 +1151,7 @@ Per Lindqvist Eric Lindvall Gregor Lingl Everett Lipman +Jake Lishman Mirko Liss Alexander Liu Hui Liu diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-24-17-30-51.gh-issue-140557.X2GETk.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-24-17-30-51.gh-issue-140557.X2GETk.rst new file mode 100644 index 00000000000..d584279a090 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-24-17-30-51.gh-issue-140557.X2GETk.rst @@ -0,0 +1,2 @@ +:class:`bytearray` buffers now have the same alignment +when empty as when allocated. Unaligned buffers can still be created by slicing. diff --git a/Misc/NEWS.d/next/Library/2026-01-07-11-57-59.gh-issue-140557.3P6-nW.rst b/Misc/NEWS.d/next/Library/2026-01-07-11-57-59.gh-issue-140557.3P6-nW.rst new file mode 100644 index 00000000000..997ad592bba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-07-11-57-59.gh-issue-140557.3P6-nW.rst @@ -0,0 +1,2 @@ +:class:`array.array` buffers now have the same alignment when empty as when +allocated. Unaligned buffers can still be created by slicing. diff --git a/Modules/_testcapi/buffer.c b/Modules/_testcapi/buffer.c index e63d4179824..48393a3dd53 100644 --- a/Modules/_testcapi/buffer.c +++ b/Modules/_testcapi/buffer.c @@ -98,6 +98,27 @@ static PyTypeObject testBufType = { .tp_members = testbuf_members }; +/* Get the pointer from a buffer-supporting object as a PyLong. + * + * Used to test alignment properties. */ +static PyObject * +buffer_pointer_as_int(PyObject *Py_UNUSED(module), PyObject *obj) +{ + PyObject *out; + Py_buffer view; + if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0) { + return NULL; + } + out = PyLong_FromVoidPtr(view.buf); + PyBuffer_Release(&view); + return out; +} + +static PyMethodDef test_methods[] = { + {"buffer_pointer_as_int", buffer_pointer_as_int, METH_O}, + {NULL}, +}; + int _PyTestCapi_Init_Buffer(PyObject *m) { if (PyType_Ready(&testBufType) < 0) { @@ -106,6 +127,9 @@ _PyTestCapi_Init_Buffer(PyObject *m) { if (PyModule_AddObjectRef(m, "testBuf", (PyObject *)&testBufType)) { return -1; } + if (PyModule_AddFunctions(m, test_methods) < 0) { + return -1; + } return 0; } diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 5769a796b18..22ec3c31fb3 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2664,7 +2664,7 @@ array_ass_subscr(PyObject *op, PyObject *item, PyObject *value) } } -static const void *emptybuf = ""; +static const _Py_ALIGNED_DEF(ALIGNOF_MAX_ALIGN_T, char) emptybuf[] = ""; static int From 04d497c284ac933488cc747b3f7082beab300848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Mon, 26 Jan 2026 16:50:27 +0100 Subject: [PATCH 082/133] gh-142119: Clarify context manager protocol documentation on `ContextVar.set` and `Token` (GH-143694) --- Doc/library/contextvars.rst | 38 +++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index b218468a084..60376e730cb 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -77,6 +77,32 @@ Context Variables to restore the variable to its previous value via the :meth:`ContextVar.reset` method. + For convenience, the token object can be used as a context manager + to avoid calling :meth:`ContextVar.reset` manually:: + + var = ContextVar('var', default='default value') + + with var.set('new value'): + assert var.get() == 'new value' + + assert var.get() == 'default value' + + It is a shorthand for:: + + var = ContextVar('var', default='default value') + + token = var.set('new value') + try: + assert var.get() == 'new value' + finally: + var.reset(token) + + assert var.get() == 'default value' + + .. versionadded:: 3.14 + + Added support for using tokens as context managers. + .. method:: reset(token) Reset the context variable to the value it had before the @@ -101,16 +127,8 @@ Context Variables the value of the variable to what it was before the corresponding *set*. - The token supports :ref:`context manager protocol ` - to restore the corresponding context variable value at the exit from - :keyword:`with` block:: - - var = ContextVar('var', default='default value') - - with var.set('new value'): - assert var.get() == 'new value' - - assert var.get() == 'default value' + Tokens support the :ref:`context manager protocol ` + to automatically reset context variables. See :meth:`ContextVar.set`. .. versionadded:: 3.14 From 933540e33217474abee3e1b53dec28ad927b6311 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jan 2026 17:15:47 +0100 Subject: [PATCH 083/133] gh-101888: Add function.__builtins__ to ref documentation (#144174) --- Doc/reference/datamodel.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index 1bfe6b7375b..f784d963f9d 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -546,6 +546,7 @@ Special read-only attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. index:: + single: __builtins__ (function attribute) single: __closure__ (function attribute) single: __globals__ (function attribute) pair: global; namespace @@ -556,6 +557,12 @@ Special read-only attributes * - Attribute - Meaning + * - .. attribute:: function.__builtins__ + - A reference to the :class:`dictionary ` that holds the function's + builtins namespace. + + .. versionadded:: 3.10 + * - .. attribute:: function.__globals__ - A reference to the :class:`dictionary ` that holds the function's :ref:`global variables ` -- the global namespace of the module From 9181d776daf87f0e4e2ce02c08f162150fdf7d79 Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" <69878+youknowone@users.noreply.github.com> Date: Tue, 27 Jan 2026 01:40:56 +0900 Subject: [PATCH 084/133] gh-142966: Make ctypes.POINTER.set_type also reset format (GH-142967) Make the deprecated set_type method resets the format, using the same code as in type initialization. Implementation note: this was done in PyCPointerType_init after calling PyCPointerType_SetProto, but was forgotten after in PyCPointerType_set_type_impl's call to PyCPointerType_SetProto. With this change, setting the format is conceptually part of setting proto (i.e. the pointed-to type). Co-authored-by: AN Long --- Lib/test/test_ctypes/test_incomplete.py | 25 ++++++++++- ...-12-19-11-30-31.gh-issue-142966.PzGiv2.rst | 1 + Modules/_ctypes/_ctypes.c | 43 ++++++++----------- 3 files changed, 44 insertions(+), 25 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-19-11-30-31.gh-issue-142966.PzGiv2.rst diff --git a/Lib/test/test_ctypes/test_incomplete.py b/Lib/test/test_ctypes/test_incomplete.py index 3189fcd1bd1..8f6316d6fba 100644 --- a/Lib/test/test_ctypes/test_incomplete.py +++ b/Lib/test/test_ctypes/test_incomplete.py @@ -1,6 +1,6 @@ import ctypes import unittest -from ctypes import Structure, POINTER, pointer, c_char_p +from ctypes import Structure, POINTER, pointer, c_char_p, c_int # String-based "incomplete pointers" were implemented in ctypes 0.6.3 (2003, when # ctypes was an external project). They made obsolete by the current @@ -50,6 +50,29 @@ class cell(Structure): lpcell.set_type(cell) self.assertIs(POINTER(cell), lpcell) + def test_set_type_updates_format(self): + # gh-142966: set_type should update StgInfo.format + # to match the element type's format + with self.assertWarns(DeprecationWarning): + lp = POINTER("node") + + class node(Structure): + _fields_ = [("value", c_int)] + + # Get the expected format before set_type + node_format = memoryview(node()).format + expected_format = "&" + node_format + + lp.set_type(node) + + # Create instance to check format via memoryview + n = node(42) + p = lp(n) + actual_format = memoryview(p).format + + # After set_type, the pointer's format should be "&" + self.assertEqual(actual_format, expected_format) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2025-12-19-11-30-31.gh-issue-142966.PzGiv2.rst b/Misc/NEWS.d/next/Library/2025-12-19-11-30-31.gh-issue-142966.PzGiv2.rst new file mode 100644 index 00000000000..92ea407c6b4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-19-11-30-31.gh-issue-142966.PzGiv2.rst @@ -0,0 +1 @@ +Fix :func:`!ctypes.POINTER.set_type` not updating the format string to match the type. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 6d9193af657..2c691c3766f 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1258,11 +1258,30 @@ PyCPointerType_SetProto(ctypes_state *st, PyObject *self, StgInfo *stginfo, PyOb return -1; } Py_XSETREF(stginfo->proto, Py_NewRef(proto)); + + // Set the format string for the pointer type based on element type. + // If info->format is NULL, this is a pointer to an incomplete type. + // We create a generic format string 'pointer to bytes' in this case. + char *new_format = NULL; STGINFO_LOCK(info); if (info->pointer_type == NULL) { Py_XSETREF(info->pointer_type, Py_NewRef(self)); } + const char *current_format = info->format ? info->format : "B"; + if (info->shape != NULL) { + // pointer to an array: the shape needs to be prefixed + new_format = _ctypes_alloc_format_string_with_shape( + info->ndim, info->shape, "&", current_format); + } else { + new_format = _ctypes_alloc_format_string("&", current_format); + } + PyMem_Free(stginfo->format); + stginfo->format = new_format; STGINFO_UNLOCK(); + + if (new_format == NULL) { + return -1; + } return 0; } @@ -1314,35 +1333,11 @@ PyCPointerType_init(PyObject *self, PyObject *args, PyObject *kwds) return -1; } if (proto) { - const char *current_format; if (PyCPointerType_SetProto(st, self, stginfo, proto) < 0) { Py_DECREF(proto); return -1; } - StgInfo *iteminfo; - if (PyStgInfo_FromType(st, proto, &iteminfo) < 0) { - Py_DECREF(proto); - return -1; - } - /* PyCPointerType_SetProto has verified proto has a stginfo. */ - assert(iteminfo); - /* If iteminfo->format is NULL, then this is a pointer to an - incomplete type. We create a generic format string - 'pointer to bytes' in this case. XXX Better would be to - fix the format string later... - */ - current_format = iteminfo->format ? iteminfo->format : "B"; - if (iteminfo->shape != NULL) { - /* pointer to an array: the shape needs to be prefixed */ - stginfo->format = _ctypes_alloc_format_string_with_shape( - iteminfo->ndim, iteminfo->shape, "&", current_format); - } else { - stginfo->format = _ctypes_alloc_format_string("&", current_format); - } Py_DECREF(proto); - if (stginfo->format == NULL) { - return -1; - } } return 0; From 7febbe6b600e63544d5e7000cf377eeead858a39 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 26 Jan 2026 20:11:40 +0200 Subject: [PATCH 085/133] gh-144001: Support ignorechars in binascii.a2b_base64() and base64.b64decode() (GH-144024) --- Doc/library/base64.rst | 13 +- Doc/library/binascii.rst | 9 ++ Doc/whatsnew/3.15.rst | 5 + .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + Lib/base64.py | 54 ++++++-- Lib/test/test_base64.py | 106 ++++++++++---- Lib/test/test_binascii.py | 51 +++++-- ...-01-19-10-26-59.gh-issue-144001.dGj8Nk.rst | 2 + Modules/binascii.c | 129 ++++++++++-------- Modules/clinic/binascii.c.h | 45 ++++-- 13 files changed, 304 insertions(+), 117 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-19-10-26-59.gh-issue-144001.dGj8Nk.rst diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 64d66fcf6bd..65b8aeaef8e 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -73,6 +73,7 @@ POST request. .. function:: b64decode(s, altchars=None, validate=False) + b64decode(s, altchars=None, validate=True, *, ignorechars) Decode the Base64 encoded :term:`bytes-like object` or ASCII string *s* and return the decoded :class:`bytes`. @@ -84,11 +85,17 @@ POST request. A :exc:`binascii.Error` exception is raised if *s* is incorrectly padded. - If *validate* is false (the default), characters that are neither + If *ignorechars* is specified, it should be a :term:`bytes-like object` + containing characters to ignore from the input when *validate* is true. + The default value of *validate* is ``True`` if *ignorechars* is specified, + ``False`` otherwise. + + If *validate* is false, characters that are neither in the normal base-64 alphabet nor the alternative alphabet are discarded prior to the padding check, but the ``+`` and ``/`` characters keep their meaning if they are not in *altchars* (they will be discarded in future Python versions). + If *validate* is true, these non-alphabet characters in the input result in a :exc:`binascii.Error`. @@ -99,6 +106,10 @@ POST request. is now deprecated. + .. versionchanged:: next + Added the *ignorechars* parameter. + + .. function:: standard_b64encode(s) Encode :term:`bytes-like object` *s* using the standard Base64 alphabet diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index eaf755711bc..d9f0baedec8 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -49,10 +49,16 @@ The :mod:`binascii` module defines the following functions: .. function:: a2b_base64(string, /, *, strict_mode=False) + a2b_base64(string, /, *, strict_mode=True, ignorechars) Convert a block of base64 data back to binary and return the binary data. More than one line may be passed at a time. + If *ignorechars* is specified, it should be a :term:`bytes-like object` + containing characters to ignore from the input when *strict_mode* is true. + The default value of *strict_mode* is ``True`` if *ignorechars* is specified, + ``False`` otherwise. + If *strict_mode* is true, only valid base64 data will be converted. Invalid base64 data will raise :exc:`binascii.Error`. @@ -66,6 +72,9 @@ The :mod:`binascii` module defines the following functions: .. versionchanged:: 3.11 Added the *strict_mode* parameter. + .. versionchanged:: next + Added the *ignorechars* parameter. + .. function:: b2a_base64(data, *, wrapcol=0, newline=True) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index aec6b1ceea3..19c01b71f02 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -444,6 +444,8 @@ base64 * Added the *wrapcol* parameter in :func:`~base64.b64encode`. (Contributed by Serhiy Storchaka in :gh:`143214`.) +* Added the *ignorechars* parameter in :func:`~base64.b64decode`. + (Contributed by Serhiy Storchaka in :gh:`144001`.) binascii -------- @@ -451,6 +453,9 @@ binascii * Added the *wrapcol* parameter in :func:`~binascii.b2a_base64`. (Contributed by Serhiy Storchaka in :gh:`143214`.) +* Added the *ignorechars* parameter in :func:`~binascii.a2b_base64`. + (Contributed by Serhiy Storchaka in :gh:`144001`.) + calendar -------- diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4a5b2a92541..fc297a2933a 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1797,6 +1797,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ident)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignore)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignorechars)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(imag)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(implieslink)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 7c2f44ef6db..563ccd7cf6d 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -520,6 +520,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(ident) STRUCT_FOR_ID(identity_hint) STRUCT_FOR_ID(ignore) + STRUCT_FOR_ID(ignorechars) STRUCT_FOR_ID(imag) STRUCT_FOR_ID(implieslink) STRUCT_FOR_ID(importlib) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 6e7bad986db..ba7c0e68434 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1795,6 +1795,7 @@ extern "C" { INIT_ID(ident), \ INIT_ID(identity_hint), \ INIT_ID(ignore), \ + INIT_ID(ignorechars), \ INIT_ID(imag), \ INIT_ID(implieslink), \ INIT_ID(importlib), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 660115931da..44063794293 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1860,6 +1860,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(ignorechars); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(imag); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/base64.py b/Lib/base64.py index 6e0da16b23c..6e9d24f0649 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -26,6 +26,8 @@ ] +_NOT_SPECIFIED = ['NOT SPECIFIED'] + bytes_types = (bytes, bytearray) # Types acceptable as binary data def _bytes_from_decode_data(s): @@ -62,7 +64,7 @@ def b64encode(s, altchars=None, *, wrapcol=0): return encoded -def b64decode(s, altchars=None, validate=False): +def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPECIFIED): """Decode the Base64 encoded bytes-like object or ASCII string s. Optional altchars must be a bytes-like object or ASCII string of length 2 @@ -72,38 +74,64 @@ def b64decode(s, altchars=None, validate=False): The result is returned as a bytes object. A binascii.Error is raised if s is incorrectly padded. - If validate is false (the default), characters that are neither in the - normal base-64 alphabet nor the alternative alphabet are discarded prior - to the padding check. If validate is true, these non-alphabet characters - in the input result in a binascii.Error. + If ignorechars is specified, it should be a byte string containing + characters to ignore from the input. The default value of validate is + True if ignorechars is specified, False otherwise. + + If validate is false, characters that are neither in the normal base-64 + alphabet nor the alternative alphabet are discarded prior to the + padding check. If validate is true, these non-alphabet characters in + the input result in a binascii.Error if they are not in ignorechars. For more information about the strict base64 check, see: https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64 """ s = _bytes_from_decode_data(s) + if validate is _NOT_SPECIFIED: + validate = ignorechars is not _NOT_SPECIFIED + if ignorechars is _NOT_SPECIFIED: + ignorechars = b'' badchar = None + badchar_strict = False if altchars is not None: altchars = _bytes_from_decode_data(altchars) if len(altchars) != 2: raise ValueError(f'invalid altchars: {altchars!r}') for b in b'+/': if b not in altchars and b in s: - badchar = b - break + if badchar is None: + badchar = b + if not validate: + break + if not isinstance(ignorechars, (bytes, bytearray)): + ignorechars = memoryview(ignorechars).cast('B') + if b not in ignorechars: + badchar_strict = True + badchar = b + break s = s.translate(bytes.maketrans(altchars, b'+/')) - result = binascii.a2b_base64(s, strict_mode=validate) + result = binascii.a2b_base64(s, strict_mode=validate, + ignorechars=ignorechars) if badchar is not None: import warnings - if validate: + if badchar_strict: warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' f'with altchars={altchars!r} and validate=True ' f'will be an error in future Python versions', DeprecationWarning, stacklevel=2) else: - warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' - f'with altchars={altchars!r} and validate=False ' - f'will be discarded in future Python versions', - FutureWarning, stacklevel=2) + ignorechars = bytes(ignorechars) + if ignorechars: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} ' + f'and ignorechars={ignorechars!r} ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) + else: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=False ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) return result diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index 6e69ece8065..5f7a41f5334 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -303,22 +303,26 @@ def test_b64decode_padding_error(self): def test_b64decode_invalid_chars(self): # issue 1466065: Test some invalid characters. - tests = ((b'%3d==', b'\xdd'), - (b'$3d==', b'\xdd'), - (b'[==', b''), - (b'YW]3=', b'am'), - (b'3{d==', b'\xdd'), - (b'3d}==', b'\xdd'), - (b'@@', b''), - (b'!', b''), - (b"YWJj\n", b"abc"), - (b'YWJj\nYWI=', b'abcab')) + tests = ((b'%3d==', b'\xdd', b'%$'), + (b'$3d==', b'\xdd', b'%$'), + (b'[==', b'', None), + (b'YW]3=', b'am', b']'), + (b'3{d==', b'\xdd', b'{}'), + (b'3d}==', b'\xdd', b'{}'), + (b'@@', b'', b'@!'), + (b'!', b'', b'@!'), + (b"YWJj\n", b"abc", b'\n'), + (b'YWJj\nYWI=', b'abcab', b'\n'), + (b'YW\nJj', b'abc', b'\n'), + (b'YW\nJj', b'abc', bytearray(b'\n')), + (b'YW\nJj', b'abc', memoryview(b'\n')), + ) funcs = ( base64.b64decode, base64.standard_b64decode, base64.urlsafe_b64decode, ) - for bstr, res in tests: + for bstr, res, ignorechars in tests: for func in funcs: with self.subTest(bstr=bstr, func=func): self.assertEqual(func(bstr), res) @@ -327,24 +331,76 @@ def test_b64decode_invalid_chars(self): base64.b64decode(bstr, validate=True) with self.assertRaises(binascii.Error): base64.b64decode(bstr.decode('ascii'), validate=True) + with self.assertRaises(binascii.Error): + # Even empty ignorechars enables the strict mode. + base64.b64decode(bstr, ignorechars=b'') + if ignorechars is not None: + r = base64.b64decode(bstr, ignorechars=ignorechars) + self.assertEqual(r, res) + + with self.assertRaises(TypeError): + base64.b64decode(b'', ignorechars='') + with self.assertRaises(TypeError): + base64.b64decode(b'', ignorechars=[]) + with self.assertRaises(TypeError): + base64.b64decode(b'', ignorechars=None) # Normal alphabet characters will be discarded when alternative given - with self.assertWarns(FutureWarning): - self.assertEqual(base64.b64decode(b'++++', altchars=b'-_'), - b'\xfb\xef\xbe') - with self.assertWarns(FutureWarning): - self.assertEqual(base64.b64decode(b'////', altchars=b'-_'), - b'\xff\xff\xff') - with self.assertWarns(DeprecationWarning): - self.assertEqual(base64.b64decode(b'++++', altchars=b'-_', validate=True), - b'\xfb\xef\xbe') - with self.assertWarns(DeprecationWarning): - self.assertEqual(base64.b64decode(b'////', altchars=b'-_', validate=True), - b'\xff\xff\xff') - with self.assertWarns(FutureWarning): + discarded = ("invalid character %a in Base64 data with %s " + "will be discarded in future Python versions") + error = ("invalid character %a in Base64 data with %s " + "will be an error in future Python versions") + with self.assertWarns(FutureWarning) as cm: + r = base64.b64decode(b'++++', altchars=b'-_') + self.assertEqual(r, b'\xfb\xef\xbe') + self.assertEqual(str(cm.warning), + discarded % ('+', "altchars=b'-_' and validate=False")) + with self.assertWarns(FutureWarning) as cm: + r = base64.b64decode(b'////', altchars=b'-_') + self.assertEqual(r, b'\xff\xff\xff') + self.assertEqual(str(cm.warning), + discarded % ('/', "altchars=b'-_' and validate=False")) + with self.assertWarns(DeprecationWarning) as cm: + r = base64.b64decode(b'++++', altchars=b'-_', validate=True) + self.assertEqual(r, b'\xfb\xef\xbe') + self.assertEqual(str(cm.warning), + error % ('+', "altchars=b'-_' and validate=True")) + with self.assertWarns(DeprecationWarning) as cm: + r = base64.b64decode(b'////', altchars=b'-_', validate=True) + self.assertEqual(r, b'\xff\xff\xff') + self.assertEqual(str(cm.warning), + error % ('/', "altchars=b'-_' and validate=True")) + with self.assertWarns(FutureWarning) as cm: + r = base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'+') + self.assertEqual(r, b'\xfb\xef\xbe') + self.assertEqual(str(cm.warning), + discarded % ('+', "altchars=b'-_' and ignorechars=b'+'")) + with self.assertWarns(FutureWarning) as cm: + r = base64.b64decode(b'////', altchars=b'-_', ignorechars=b'/') + self.assertEqual(r, b'\xff\xff\xff') + self.assertEqual(str(cm.warning), + discarded % ('/', "altchars=b'-_' and ignorechars=b'/'")) + with self.assertWarns(DeprecationWarning) as cm: + r = base64.b64decode(b'++++////', altchars=b'-_', ignorechars=b'+') + self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff') + self.assertEqual(str(cm.warning), + error % ('/', "altchars=b'-_' and validate=True")) + with self.assertWarns(DeprecationWarning) as cm: + r = base64.b64decode(b'++++////', altchars=b'-_', ignorechars=b'/') + self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff') + self.assertEqual(str(cm.warning), + error % ('+', "altchars=b'-_' and validate=True")) + + with self.assertWarns(FutureWarning) as cm: self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe') - with self.assertWarns(FutureWarning): + self.assertEqual(str(cm.warning), + "invalid character '+' in URL-safe Base64 data " + "will be discarded in future Python versions") + with self.assertWarns(FutureWarning) as cm: self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff') + self.assertEqual(str(cm.warning), + "invalid character '/' in URL-safe Base64 data " + "will be discarded in future Python versions") with self.assertRaises(binascii.Error): base64.b64decode(b'+/!', altchars=b'-_') diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py index 47e1e6ab035..4cfc332e89b 100644 --- a/Lib/test/test_binascii.py +++ b/Lib/test/test_binascii.py @@ -145,16 +145,16 @@ def assertExcessPadding(data, non_strict_mode_expected_result: bytes): # Test excess data exceptions assertExcessData(b'ab==a', b'i') - assertExcessData(b'ab===', b'i') - assertExcessData(b'ab====', b'i') - assertExcessData(b'ab==:', b'i') + assertExcessPadding(b'ab===', b'i') + assertExcessPadding(b'ab====', b'i') + assertNonBase64Data(b'ab==:', b'i') assertExcessData(b'abc=a', b'i\xb7') - assertExcessData(b'abc=:', b'i\xb7') - assertExcessData(b'ab==\n', b'i') - assertExcessData(b'abc==', b'i\xb7') - assertExcessData(b'abc===', b'i\xb7') - assertExcessData(b'abc====', b'i\xb7') - assertExcessData(b'abc=====', b'i\xb7') + assertNonBase64Data(b'abc=:', b'i\xb7') + assertNonBase64Data(b'ab==\n', b'i') + assertExcessPadding(b'abc==', b'i\xb7') + assertExcessPadding(b'abc===', b'i\xb7') + assertExcessPadding(b'abc====', b'i\xb7') + assertExcessPadding(b'abc=====', b'i\xb7') # Test non-base64 data exceptions assertNonBase64Data(b'\nab==', b'i') @@ -170,12 +170,45 @@ def assertExcessPadding(data, non_strict_mode_expected_result: bytes): assertLeadingPadding(b'=====', b'') assertDiscontinuousPadding(b'ab=c=', b'i\xb7') assertDiscontinuousPadding(b'ab=ab==', b'i\xb6\x9b') + assertNonBase64Data(b'ab=:=', b'i') assertExcessPadding(b'abcd=', b'i\xb7\x1d') assertExcessPadding(b'abcd==', b'i\xb7\x1d') assertExcessPadding(b'abcd===', b'i\xb7\x1d') assertExcessPadding(b'abcd====', b'i\xb7\x1d') assertExcessPadding(b'abcd=====', b'i\xb7\x1d') + def test_base64_invalidchars(self): + def assertNonBase64Data(data, expected, ignorechars): + data = self.type2test(data) + assert_regex = r'(?i)Only base64 data' + self.assertEqual(binascii.a2b_base64(data), expected) + with self.assertRaisesRegex(binascii.Error, assert_regex): + binascii.a2b_base64(data, strict_mode=True) + with self.assertRaisesRegex(binascii.Error, assert_regex): + binascii.a2b_base64(data, ignorechars=b'') + self.assertEqual(binascii.a2b_base64(data, ignorechars=ignorechars), + expected) + self.assertEqual(binascii.a2b_base64(data, strict_mode=False, ignorechars=b''), + expected) + + assertNonBase64Data(b'\nab==', b'i', ignorechars=b'\n') + assertNonBase64Data(b'ab:(){:|:&};:==', b'i', ignorechars=b':;(){}|&') + assertNonBase64Data(b'a\nb==', b'i', ignorechars=b'\n') + assertNonBase64Data(b'a\x00b==', b'i', ignorechars=b'\x00') + assertNonBase64Data(b'ab==:', b'i', ignorechars=b':') + assertNonBase64Data(b'abc=:', b'i\xb7', ignorechars=b':') + assertNonBase64Data(b'ab==\n', b'i', ignorechars=b'\n') + assertNonBase64Data(b'ab=:=', b'i', ignorechars=b':') + assertNonBase64Data(b'a\nb==', b'i', ignorechars=bytearray(b'\n')) + assertNonBase64Data(b'a\nb==', b'i', ignorechars=memoryview(b'\n')) + + data = self.type2test(b'a\nb==') + with self.assertRaises(TypeError): + binascii.a2b_base64(data, ignorechars='') + with self.assertRaises(TypeError): + binascii.a2b_base64(data, ignorechars=[]) + with self.assertRaises(TypeError): + binascii.a2b_base64(data, ignorechars=None) def test_base64errors(self): # Test base64 with invalid padding diff --git a/Misc/NEWS.d/next/Library/2026-01-19-10-26-59.gh-issue-144001.dGj8Nk.rst b/Misc/NEWS.d/next/Library/2026-01-19-10-26-59.gh-issue-144001.dGj8Nk.rst new file mode 100644 index 00000000000..02d453f4d2c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-19-10-26-59.gh-issue-144001.dGj8Nk.rst @@ -0,0 +1,2 @@ +Added the *ignorechars* parameter in :func:`binascii.a2b_base64` and +:func:`base64.b64decode`. diff --git a/Modules/binascii.c b/Modules/binascii.c index c569d3187f2..593b27ac5ed 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -469,32 +469,45 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) return PyBytesWriter_FinishWithPointer(writer, ascii_data); } + +static int +ignorechar(unsigned char c, Py_buffer *ignorechars) +{ + return (ignorechars->buf != NULL && + memchr(ignorechars->buf, c, ignorechars->len)); +} + /*[clinic input] -@permit_long_docstring_body binascii.a2b_base64 data: ascii_buffer / * - strict_mode: bool = False + strict_mode: bool(c_default="-1", py_default="") = False + When set to true, bytes that are not part of the base64 standard are + not allowed. The same applies to excess data after padding (= / ==). + Set to True by default if ignorechars is specified, False otherwise. + ignorechars: Py_buffer(py_default="") = None + A byte string containing characters to ignore from the input when + strict_mode is true. Decode a line of base64 data. - - strict_mode - When set to True, bytes that are not part of the base64 standard are not allowed. - The same applies to excess data after padding (= / ==). [clinic start generated code]*/ static PyObject * -binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) -/*[clinic end generated code: output=5409557788d4f975 input=13c797187acc9c40]*/ +binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, + Py_buffer *ignorechars) +/*[clinic end generated code: output=eab37aea4cfa6daa input=3be4937d72943835]*/ { assert(data->len >= 0); const unsigned char *ascii_data = data->buf; size_t ascii_len = data->len; binascii_state *state = NULL; - char padding_started = 0; + + if (strict_mode == -1) { + strict_mode = (ignorechars->buf != NULL); + } /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ @@ -504,14 +517,6 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) } unsigned char *bin_data = PyBytesWriter_GetData(writer); - if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { - state = get_binascii_state(module); - if (state) { - PyErr_SetString(state->Error, "Leading padding not allowed"); - } - goto error_end; - } - size_t i = 0; /* Current position in input */ /* Fast path: use optimized decoder for complete quads. @@ -538,36 +543,44 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) ** the invalid ones. */ if (this_ch == BASE64_PAD) { - padding_started = 1; + pads++; - if (strict_mode && quad_pos == 0) { - state = get_binascii_state(module); - if (state) { - PyErr_SetString(state->Error, "Excess padding not allowed"); - } - goto error_end; - } - if (quad_pos >= 2 && quad_pos + ++pads >= 4) { - /* A pad sequence means we should not parse more input. - ** We've already interpreted the data from the quad at this point. - ** in strict mode, an error should raise if there's excess data after the padding. - */ - if (strict_mode && i + 1 < ascii_len) { + if (strict_mode) { + if (quad_pos == 0) { state = get_binascii_state(module); if (state) { - PyErr_SetString(state->Error, "Excess data after padding"); + PyErr_SetString(state->Error, (i == 0) + ? "Leading padding not allowed" + : "Excess padding not allowed"); } goto error_end; } - - goto done; + if (quad_pos == 1) { + /* Set an error below. */ + break; + } + if (quad_pos + pads > 4) { + state = get_binascii_state(module); + if (state) { + PyErr_SetString(state->Error, "Excess padding not allowed"); + } + goto error_end; + } + } + else { + if (quad_pos >= 2 && quad_pos + pads >= 4) { + /* A pad sequence means we should not parse more input. + ** We've already interpreted the data from the quad at this point. + */ + goto done; + } } continue; } - this_ch = table_a2b_base64[this_ch]; - if (this_ch >= 64) { - if (strict_mode) { + unsigned char v = table_a2b_base64[this_ch]; + if (v >= 64) { + if (strict_mode && !ignorechar(this_ch, ignorechars)) { state = get_binascii_state(module); if (state) { PyErr_SetString(state->Error, "Only base64 data is allowed"); @@ -578,10 +591,12 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) } // Characters that are not '=', in the middle of the padding, are not allowed - if (strict_mode && padding_started) { + if (strict_mode && pads) { state = get_binascii_state(module); if (state) { - PyErr_SetString(state->Error, "Discontinuous padding not allowed"); + PyErr_SetString(state->Error, (quad_pos + pads == 4) + ? "Excess data after padding" + : "Discontinuous padding not allowed"); } goto error_end; } @@ -590,44 +605,46 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) switch (quad_pos) { case 0: quad_pos = 1; - leftchar = this_ch; + leftchar = v; break; case 1: quad_pos = 2; - *bin_data++ = (leftchar << 2) | (this_ch >> 4); - leftchar = this_ch & 0x0f; + *bin_data++ = (leftchar << 2) | (v >> 4); + leftchar = v & 0x0f; break; case 2: quad_pos = 3; - *bin_data++ = (leftchar << 4) | (this_ch >> 2); - leftchar = this_ch & 0x03; + *bin_data++ = (leftchar << 4) | (v >> 2); + leftchar = v & 0x03; break; case 3: quad_pos = 0; - *bin_data++ = (leftchar << 6) | (this_ch); + *bin_data++ = (leftchar << 6) | (v); leftchar = 0; break; } } - if (quad_pos != 0) { + if (quad_pos == 1) { + /* There is exactly one extra valid, non-padding, base64 character. + ** This is an invalid length, as there is no possible input that + ** could encoded into such a base64 string. + */ state = get_binascii_state(module); - if (state == NULL) { - /* error already set, from get_binascii_state */ - assert(PyErr_Occurred()); - } else if (quad_pos == 1) { - /* - ** There is exactly one extra valid, non-padding, base64 character. - ** This is an invalid length, as there is no possible input that - ** could encoded into such a base64 string. - */ + if (state) { unsigned char *bin_data_start = PyBytesWriter_GetData(writer); PyErr_Format(state->Error, "Invalid base64-encoded string: " "number of data characters (%zd) cannot be 1 more " "than a multiple of 4", (bin_data - bin_data_start) / 3 * 4 + 1); - } else { + } + goto error_end; + } + + if (quad_pos != 0 && quad_pos + pads != 4) { + state = get_binascii_state(module); + if (state) { PyErr_SetString(state->Error, "Incorrect padding"); } goto error_end; diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h index 524f5fc93d0..91325b1bddd 100644 --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -116,20 +116,26 @@ exit: } PyDoc_STRVAR(binascii_a2b_base64__doc__, -"a2b_base64($module, data, /, *, strict_mode=False)\n" +"a2b_base64($module, data, /, *, strict_mode=,\n" +" ignorechars=)\n" "--\n" "\n" "Decode a line of base64 data.\n" "\n" " strict_mode\n" -" When set to True, bytes that are not part of the base64 standard are not allowed.\n" -" The same applies to excess data after padding (= / ==)."); +" When set to true, bytes that are not part of the base64 standard are\n" +" not allowed. The same applies to excess data after padding (= / ==).\n" +" Set to True by default if ignorechars is specified, False otherwise.\n" +" ignorechars\n" +" A byte string containing characters to ignore from the input when\n" +" strict_mode is true."); #define BINASCII_A2B_BASE64_METHODDEF \ {"a2b_base64", _PyCFunction_CAST(binascii_a2b_base64), METH_FASTCALL|METH_KEYWORDS, binascii_a2b_base64__doc__}, static PyObject * -binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode); +binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, + Py_buffer *ignorechars); static PyObject * binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -137,7 +143,7 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 1 + #define NUM_KEYWORDS 2 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -146,7 +152,7 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(strict_mode), }, + .ob_item = { &_Py_ID(strict_mode), &_Py_ID(ignorechars), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -155,17 +161,18 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"", "strict_mode", NULL}; + static const char * const _keywords[] = {"", "strict_mode", "ignorechars", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "a2b_base64", .kwtuple = KWTUPLE, }; #undef KWTUPLE - PyObject *argsbuf[2]; + PyObject *argsbuf[3]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; Py_buffer data = {NULL, NULL}; - int strict_mode = 0; + int strict_mode = -1; + Py_buffer ignorechars = {NULL, NULL}; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); @@ -178,17 +185,29 @@ binascii_a2b_base64(PyObject *module, PyObject *const *args, Py_ssize_t nargs, P if (!noptargs) { goto skip_optional_kwonly; } - strict_mode = PyObject_IsTrue(args[1]); - if (strict_mode < 0) { + if (args[1]) { + strict_mode = PyObject_IsTrue(args[1]); + if (strict_mode < 0) { + goto exit; + } + if (!--noptargs) { + goto skip_optional_kwonly; + } + } + if (PyObject_GetBuffer(args[2], &ignorechars, PyBUF_SIMPLE) != 0) { goto exit; } skip_optional_kwonly: - return_value = binascii_a2b_base64_impl(module, &data, strict_mode); + return_value = binascii_a2b_base64_impl(module, &data, strict_mode, &ignorechars); exit: /* Cleanup for data */ if (data.obj) PyBuffer_Release(&data); + /* Cleanup for ignorechars */ + if (ignorechars.obj) { + PyBuffer_Release(&ignorechars); + } return return_value; } @@ -823,4 +842,4 @@ exit: return return_value; } -/*[clinic end generated code: output=644ccdc8e0d56e65 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=13f0a4b0f5d3fcb4 input=a9049054013a1b77]*/ From 25206173619f5f387c88eb258948adcfe66d4966 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 26 Jan 2026 23:15:21 +0200 Subject: [PATCH 086/133] gh-142037: Fix a refleak introduced in GH-142081 (GH-144256) --- Objects/bytesobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b85cbfe43e1..00c1c63b8e0 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1156,6 +1156,7 @@ _PyBytes_FormatEx(const char *format, Py_ssize_t format_len, goto error; } + Py_XDECREF(key); if (args_owned) { Py_DECREF(args); } From 3e9a5b022f01fa95b4485fcf2c0c87bfb9fff837 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 27 Jan 2026 00:15:16 -0700 Subject: [PATCH 087/133] gh-144257: document return values of PyModule_SetDocString (GH-144258) Co-authored-by: sobolevn --- Doc/c-api/module.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 431151b841e..90f55add56b 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -1021,6 +1021,9 @@ or code that creates modules dynamically. ``PyModuleDef`` (such as when using :ref:`multi-phase-initialization`, ``PyModule_Create``, or ``PyModule_FromDefAndSpec``). + Return ``0`` on success. + Return ``-1`` with an exception set on error. + .. versionadded:: 3.5 .. c:function:: int PyUnstable_Module_SetGIL(PyObject *module, void *gil) From 487bd2dea538e36cb620dd9e0f298d731b9ede8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Tue, 27 Jan 2026 10:49:05 +0100 Subject: [PATCH 088/133] gh-142119: Clarify that one `contextvars.Token` can only reset once in a lifetime (GH-143693) --- Doc/library/contextvars.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 60376e730cb..653d8b597c2 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -119,13 +119,15 @@ Context Variables # After the reset call the var has no value again, so # var.get() would raise a LookupError. + The same *token* cannot be used twice. + .. class:: Token *Token* objects are returned by the :meth:`ContextVar.set` method. They can be passed to the :meth:`ContextVar.reset` method to revert the value of the variable to what it was before the corresponding - *set*. + *set*. A single token cannot reset a context variable more than once. Tokens support the :ref:`context manager protocol ` to automatically reset context variables. See :meth:`ContextVar.set`. From 17d447e993a0ff9b7d44786ceb2a8f9510638bfa Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 27 Jan 2026 02:05:09 -0800 Subject: [PATCH 089/133] gh-126014: test_makefile_test_folders: Ignore basically-empty directories (#140466) The code in test_makefile was attempting to ignore any non-interesting files, but missed some corners: 1. There is never a *file* called `__pycache__`. 2. A directory containing only a `__pycache__` subdirectory should be ignored. 3. A directory containing only hidden files should be ignored. Simplify this all into a couple of filters that let us check for empty lists. --- Lib/test/test_tools/test_makefile.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_tools/test_makefile.py b/Lib/test/test_tools/test_makefile.py index 4c7588d4d93..31a51606739 100644 --- a/Lib/test/test_tools/test_makefile.py +++ b/Lib/test/test_tools/test_makefile.py @@ -48,15 +48,18 @@ def test_makefile_test_folders(self): if dirname == '__pycache__' or dirname.startswith('.'): dirs.clear() # do not process subfolders continue - # Skip empty dirs: + + # Skip empty dirs (ignoring hidden files and __pycache__): + files = [ + filename for filename in files + if not filename.startswith('.') + ] + dirs = [ + dirname for dirname in dirs + if not dirname.startswith('.') and dirname != "__pycache__" + ] if not dirs and not files: continue - # Skip dirs with hidden-only files: - if files and all( - filename.startswith('.') or filename == '__pycache__' - for filename in files - ): - continue relpath = os.path.relpath(dirpath, support.STDLIB_DIR) with self.subTest(relpath=relpath): From f2b5c206c788d3a5bf2ab7c63fb69d3b802646f4 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 27 Jan 2026 03:28:28 -0700 Subject: [PATCH 090/133] gh-143883: Use named parameters in PyModExport-related declarations & docs (GH-143884) --- Doc/c-api/module.rst | 10 +++++----- Include/moduleobject.h | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index 90f55add56b..e8a6e09f555 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -426,10 +426,10 @@ To retrieve the state from a given module, use the following functions: module state. -.. c:function:: int PyModule_GetStateSize(PyObject *, Py_ssize_t *result) +.. c:function:: int PyModule_GetStateSize(PyObject *module, Py_ssize_t *result) - Set *\*result* to the size of the module's state, as specified using - :c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`), + Set *\*result* to the size of *module*'s state, as specified + using :c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`), and return 0. On error, set *\*result* to -1, and return -1 with an exception set. @@ -597,7 +597,7 @@ A module's token -- and the *your_token* value to use in the above code -- is: .. c:function:: int PyModule_GetToken(PyObject *module, void** result) - Set *\*result* to the module's token and return 0. + Set *\*result* to the module token for *module* and return 0. On error, set *\*result* to NULL, and return -1 with an exception set. @@ -645,7 +645,7 @@ rather than from an extension's :ref:`export hook `. .. c:function:: int PyModule_Exec(PyObject *module) - Execute the :c:data:`Py_mod_exec` slot(s) of the given *module*. + Execute the :c:data:`Py_mod_exec` slot(s) of *module*. On success, return 0. On error, return -1 with an exception set. diff --git a/Include/moduleobject.h b/Include/moduleobject.h index e83bc395aa4..d1dde7982ad 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -118,11 +118,11 @@ PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) -PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *, +PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec); -PyAPI_FUNC(int) PyModule_Exec(PyObject *mod); -PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *mod, Py_ssize_t *result); -PyAPI_FUNC(int) PyModule_GetToken(PyObject *, void **result); +PyAPI_FUNC(int) PyModule_Exec(PyObject *module); +PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *module, Py_ssize_t *result); +PyAPI_FUNC(int) PyModule_GetToken(PyObject *module, void **result); #endif #ifndef _Py_OPAQUE_PYOBJECT From 197e4c06289e282857fc953cc1a27c209e3c03a7 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 27 Jan 2026 03:39:03 -0800 Subject: [PATCH 091/133] Avoid TestNullDlsym hanging on HP-PA (#141011) glibc has no support for IFUNC on HP PA RISC yet. Rather than waiting for an "OK" that we'll never get, skip the test. See: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/hppa/dl-irel.h;h=770dcb3ea3a6ce232bb11bf59315cfec4c543f93;hb=HEAD --- Lib/test/test_ctypes/test_dlerror.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ctypes/test_dlerror.py b/Lib/test/test_ctypes/test_dlerror.py index 5658234f9ec..bb0aec0b3c5 100644 --- a/Lib/test/test_ctypes/test_dlerror.py +++ b/Lib/test/test_ctypes/test_dlerror.py @@ -30,8 +30,9 @@ """ -@unittest.skipUnless(sys.platform.startswith('linux'), - 'test requires GNU IFUNC support') +@unittest.skipIf(not sys.platform.startswith('linux') + or platform.machine().startswith('parisc'), + 'test requires GNU IFUNC support') @unittest.skipIf(test.support.linked_to_musl(), "Requires glibc") class TestNullDlsym(unittest.TestCase): """GH-126554: Ensure that we catch NULL dlsym return values From 66055d06503398e0a90515ebe2c120de93ad830d Mon Sep 17 00:00:00 2001 From: Diego Russo Date: Tue, 27 Jan 2026 13:17:40 +0000 Subject: [PATCH 092/133] GH-126910: add test for manual frame unwinding (#144137) --- Include/internal/pycore_jit.h | 1 + Lib/test/test_frame_pointer_unwind.py | 221 +++++++++++++++++++++ Modules/_testinternalcapi.c | 274 ++++++++++++++++++++++++++ Python/jit.c | 45 ++++- 4 files changed, 539 insertions(+), 2 deletions(-) create mode 100644 Lib/test/test_frame_pointer_unwind.py diff --git a/Include/internal/pycore_jit.h b/Include/internal/pycore_jit.h index 89d5bb53643..70bccce4166 100644 --- a/Include/internal/pycore_jit.h +++ b/Include/internal/pycore_jit.h @@ -26,6 +26,7 @@ typedef _Py_CODEUNIT *(*jit_func)( int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length); void _PyJIT_Free(_PyExecutorObject *executor); void _PyJIT_Fini(void); +PyAPI_FUNC(int) _PyJIT_AddressInJitCode(PyInterpreterState *interp, uintptr_t addr); #endif // _Py_JIT diff --git a/Lib/test/test_frame_pointer_unwind.py b/Lib/test/test_frame_pointer_unwind.py new file mode 100644 index 00000000000..5804cc7e1d7 --- /dev/null +++ b/Lib/test/test_frame_pointer_unwind.py @@ -0,0 +1,221 @@ +import json +import os +import platform +import subprocess +import sys +import sysconfig +import unittest + +from test import support +from test.support import import_helper + + +_testinternalcapi = import_helper.import_module("_testinternalcapi") + + +if not support.has_subprocess_support: + raise unittest.SkipTest("test requires subprocess support") + + +def _frame_pointers_expected(machine): + cflags = " ".join( + value for value in ( + sysconfig.get_config_var("PY_CORE_CFLAGS"), + sysconfig.get_config_var("CFLAGS"), + ) + if value + ) + if "no-omit-frame-pointer" in cflags: + return True + if "omit-frame-pointer" in cflags: + return False + if sys.platform == "darwin": + # macOS x86_64/ARM64 always have frame pointer by default. + return True + if sys.platform == "linux": + if machine in {"aarch64", "arm64"}: + # 32-bit Linux is not supported + if sys.maxsize < 2**32: + return None + return True + if machine == "x86_64": + return False + if sys.platform == "win32": + # MSVC ignores /Oy and /Oy- on x64/ARM64. + if machine == "arm64": + # Windows ARM64 guidelines recommend frame pointers (x29) for stack walking. + return True + elif machine == "x86_64": + # Windows x64 uses unwind metadata; frame pointers are not required. + return None + return None + + +def _build_stack_and_unwind(): + import operator + + def build_stack(n, unwinder, warming_up_caller=False): + if warming_up_caller: + return + if n == 0: + return unwinder() + warming_up = True + while warming_up: + # Can't branch on JIT state inside JITted code, so compute here. + warming_up = ( + hasattr(sys, "_jit") + and sys._jit.is_enabled() + and not sys._jit.is_active() + ) + result = operator.call(build_stack, n - 1, unwinder, warming_up) + return result + + stack = build_stack(10, _testinternalcapi.manual_frame_pointer_unwind) + return stack + + +def _classify_stack(stack, jit_enabled): + labels = _testinternalcapi.classify_stack_addresses(stack, jit_enabled) + + annotated = [] + jit_frames = 0 + python_frames = 0 + other_frames = 0 + for idx, (frame, tag) in enumerate(zip(stack, labels)): + addr = int(frame) + if tag == "jit": + jit_frames += 1 + elif tag == "python": + python_frames += 1 + else: + other_frames += 1 + annotated.append((idx, addr, tag)) + return annotated, python_frames, jit_frames, other_frames + + +def _annotate_unwind(): + stack = _build_stack_and_unwind() + jit_enabled = hasattr(sys, "_jit") and sys._jit.is_enabled() + jit_backend = _testinternalcapi.get_jit_backend() + ranges = _testinternalcapi.get_jit_code_ranges() if jit_enabled else [] + if jit_enabled and ranges: + print("JIT ranges:") + for start, end in ranges: + print(f" {int(start):#x}-{int(end):#x}") + annotated, python_frames, jit_frames, other_frames = _classify_stack( + stack, jit_enabled + ) + for idx, addr, tag in annotated: + print(f"#{idx:02d} {addr:#x} -> {tag}") + return json.dumps({ + "length": len(stack), + "python_frames": python_frames, + "jit_frames": jit_frames, + "other_frames": other_frames, + "jit_backend": jit_backend, + }) + + +def _manual_unwind_length(**env): + code = ( + "from test.test_frame_pointer_unwind import _annotate_unwind; " + "print(_annotate_unwind());" + ) + run_env = os.environ.copy() + run_env.update(env) + proc = subprocess.run( + [sys.executable, "-c", code], + env=run_env, + capture_output=True, + text=True, + ) + # Surface the output for debugging/visibility when running this test + if proc.stdout: + print(proc.stdout, end="") + if proc.returncode: + raise RuntimeError( + f"unwind helper failed (rc={proc.returncode}): {proc.stderr or proc.stdout}" + ) + stdout_lines = proc.stdout.strip().splitlines() + if not stdout_lines: + raise RuntimeError("unwind helper produced no output") + try: + return json.loads(stdout_lines[-1]) + except ValueError as exc: + raise RuntimeError( + f"unexpected output from unwind helper: {proc.stdout!r}" + ) from exc + + +@support.requires_gil_enabled("test requires the GIL enabled") +@unittest.skipIf(support.is_wasi, "test not supported on WASI") +class FramePointerUnwindTests(unittest.TestCase): + + def setUp(self): + super().setUp() + machine = platform.machine().lower() + expected = _frame_pointers_expected(machine) + if expected is None: + self.skipTest(f"unsupported architecture for frame pointer check: {machine}") + try: + _testinternalcapi.manual_frame_pointer_unwind() + except RuntimeError as exc: + if "not supported" in str(exc): + self.skipTest("manual frame pointer unwinding not supported on this platform") + raise + self.machine = machine + self.frame_pointers_expected = expected + + def test_manual_unwind_respects_frame_pointers(self): + jit_available = hasattr(sys, "_jit") and sys._jit.is_available() + envs = [({"PYTHON_JIT": "0"}, False)] + if jit_available: + envs.append(({"PYTHON_JIT": "1"}, True)) + + for env, using_jit in envs: + with self.subTest(env=env): + result = _manual_unwind_length(**env) + jit_frames = result["jit_frames"] + python_frames = result.get("python_frames", 0) + jit_backend = result.get("jit_backend") + if self.frame_pointers_expected: + self.assertGreater( + python_frames, + 0, + f"expected to find Python frames on {self.machine} with env {env}", + ) + if using_jit: + if jit_backend == "jit": + self.assertGreater( + jit_frames, + 0, + f"expected to find JIT frames on {self.machine} with env {env}", + ) + else: + # jit_backend is "interpreter" or not present + self.assertEqual( + jit_frames, + 0, + f"unexpected JIT frames counted on {self.machine} with env {env}", + ) + else: + self.assertEqual( + jit_frames, + 0, + f"unexpected JIT frames counted on {self.machine} with env {env}", + ) + else: + self.assertLessEqual( + python_frames, + 1, + f"unexpected Python frames counted on {self.machine} with env {env}", + ) + self.assertEqual( + jit_frames, + 0, + f"unexpected JIT frames counted on {self.machine} with env {env}", + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 8d63b3e55fc..22cfa3f58a9 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -10,6 +10,7 @@ #undef NDEBUG #include "Python.h" +#include #include "pycore_backoff.h" // JUMP_BACKWARD_INITIAL_VALUE #include "pycore_bitutils.h" // _Py_bswap32() #include "pycore_bytesobject.h" // _PyBytes_Find() @@ -28,6 +29,7 @@ #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() #include "pycore_instruction_sequence.h" // _PyInstructionSequence_New() #include "pycore_interpframe.h" // _PyFrame_GetFunction() +#include "pycore_jit.h" // _PyJIT_AddressInJitCode() #include "pycore_object.h" // _PyObject_IsFreed() #include "pycore_optimizer.h" // _Py_Executor_DependsOn #include "pycore_pathconfig.h" // _PyPathConfig_ClearGlobal() @@ -42,10 +44,22 @@ // Include test definitions from _testinternalcapi/ #include "_testinternalcapi/parts.h" +#if defined(HAVE_DLADDR) && !defined(__wasi__) +# include +#endif +#ifdef MS_WINDOWS +# include +# include +# include +# include +#endif #define MODULE_NAME "_testinternalcapi" +static const uintptr_t min_frame_pointer_addr = 0x1000; + + static PyObject * _get_current_module(void) { @@ -139,6 +153,262 @@ get_stack_margin(PyObject *self, PyObject *Py_UNUSED(args)) return PyLong_FromSize_t(_PyOS_STACK_MARGIN_BYTES); } +#ifdef MS_WINDOWS +static const char * +classify_address(uintptr_t addr, int jit_enabled, PyInterpreterState *interp) +{ + HMODULE module = NULL; + if (GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCWSTR)addr, + &module)) { + wchar_t path[MAX_PATH]; + DWORD len = GetModuleFileNameW(module, path, Py_ARRAY_LENGTH(path)); + if (len > 0 && len < Py_ARRAY_LENGTH(path)) { + const wchar_t *base = wcsrchr(path, L'\\'); + base = base ? base + 1 : path; + if (_wcsnicmp(base, L"python", 6) == 0) { + return "python"; + } + return "other"; + } + /* Module resolved but path unavailable: treat as non-JIT. */ + return "other"; + } +#ifdef _Py_JIT + if (jit_enabled && _PyJIT_AddressInJitCode(interp, addr)) { + return "jit"; + } +#endif + return "other"; +} +#elif defined(HAVE_DLADDR) && !defined(__wasi__) +static const char * +classify_address(uintptr_t addr, int jit_enabled, PyInterpreterState *interp) +{ + Dl_info info; + if (dladdr((void *)addr, &info) != 0 + && info.dli_fname != NULL + && info.dli_fname[0] != '\0') { + const char *base = strrchr(info.dli_fname, '/'); + base = base ? base + 1 : info.dli_fname; + if (strncmp(base, "python", 6) == 0) { + return "python"; + } + return "other"; + } +#ifdef _Py_JIT + if (jit_enabled && _PyJIT_AddressInJitCode(interp, addr)) { + return "jit"; + } +#endif + return "other"; +} +#else +static const char * +classify_address(uintptr_t addr, int jit_enabled, PyInterpreterState *interp) +{ +#ifdef _Py_JIT + if (jit_enabled && _PyJIT_AddressInJitCode(interp, addr)) { + return "jit"; + } +#endif + return "other"; +} +#endif + +static PyObject * +classify_stack_addresses(PyObject *self, PyObject *args) +{ + PyObject *seq = NULL; + int jit_enabled = 0; + + if (!PyArg_ParseTuple(args, "O|p:classify_stack_addresses", + &seq, &jit_enabled)) { + return NULL; + } + PyObject *fast = PySequence_Fast(seq, "addresses must be iterable"); + if (fast == NULL) { + return NULL; + } + Py_ssize_t n = PySequence_Fast_GET_SIZE(fast); + PyObject *labels = PyList_New(n); + if (labels == NULL) { + Py_DECREF(fast); + return NULL; + } + PyThreadState *tstate = _PyThreadState_GET(); + PyInterpreterState *interp = tstate ? tstate->interp : NULL; + PyObject **items = PySequence_Fast_ITEMS(fast); + for (Py_ssize_t i = 0; i < n; i++) { + unsigned long long value = PyLong_AsUnsignedLongLong(items[i]); + if (PyErr_Occurred()) { + Py_DECREF(labels); + Py_DECREF(fast); + return NULL; + } + const char *label = classify_address((uintptr_t)value, jit_enabled, interp); + PyObject *label_obj = PyUnicode_FromString(label); + if (label_obj == NULL) { + Py_DECREF(labels); + Py_DECREF(fast); + return NULL; + } + PyList_SET_ITEM(labels, i, label_obj); + } + Py_DECREF(fast); + return labels; +} + +static PyObject * +get_jit_code_ranges(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyObject *ranges = PyList_New(0); + if (ranges == NULL) { + return NULL; + } +#ifdef _Py_JIT + PyThreadState *tstate = _PyThreadState_GET(); + PyInterpreterState *interp = tstate ? tstate->interp : NULL; + if (interp == NULL) { + return ranges; + } + for (_PyExecutorObject *exec = interp->executor_list_head; + exec != NULL; + exec = exec->vm_data.links.next) + { + if (exec->jit_code == NULL || exec->jit_size == 0) { + continue; + } + uintptr_t start = (uintptr_t)exec->jit_code; + uintptr_t end = start + exec->jit_size; + PyObject *start_obj = PyLong_FromUnsignedLongLong(start); + PyObject *end_obj = PyLong_FromUnsignedLongLong(end); + if (start_obj == NULL || end_obj == NULL) { + Py_XDECREF(start_obj); + Py_XDECREF(end_obj); + Py_DECREF(ranges); + return NULL; + } + PyObject *pair = PyTuple_New(2); + if (pair == NULL) { + Py_DECREF(start_obj); + Py_DECREF(end_obj); + Py_DECREF(ranges); + return NULL; + } + PyTuple_SET_ITEM(pair, 0, start_obj); + PyTuple_SET_ITEM(pair, 1, end_obj); + if (PyList_Append(ranges, pair) < 0) { + Py_DECREF(pair); + Py_DECREF(ranges); + return NULL; + } + Py_DECREF(pair); + } +#endif + return ranges; +} + +static PyObject * +get_jit_backend(PyObject *self, PyObject *Py_UNUSED(args)) +{ +#ifdef _Py_JIT + return PyUnicode_FromString("jit"); +#elif defined(_Py_TIER2) + return PyUnicode_FromString("interpreter"); +#else + Py_RETURN_NONE; +#endif +} + +static PyObject * +manual_unwind_from_fp(uintptr_t *frame_pointer) +{ + Py_ssize_t max_depth = 200; + int stack_grows_down = _Py_STACK_GROWS_DOWN; + + if (frame_pointer == NULL) { + return PyList_New(0); + } + + PyObject *result = PyList_New(0); + if (result == NULL) { + return NULL; + } + + for (Py_ssize_t depth = 0; + depth < max_depth && frame_pointer != NULL; + depth++) + { + uintptr_t fp_addr = (uintptr_t)frame_pointer; + if ((fp_addr % sizeof(uintptr_t)) != 0) { + break; + } + uintptr_t return_addr = frame_pointer[1]; + + PyObject *addr_obj = PyLong_FromUnsignedLongLong(return_addr); + if (addr_obj == NULL) { + Py_DECREF(result); + return NULL; + } + if (PyList_Append(result, addr_obj) < 0) { + Py_DECREF(addr_obj); + Py_DECREF(result); + return NULL; + } + Py_DECREF(addr_obj); + + uintptr_t *next_fp = (uintptr_t *)frame_pointer[0]; + // Stop if the frame pointer is extremely low. + if ((uintptr_t)next_fp < min_frame_pointer_addr) { + break; + } + uintptr_t next_addr = (uintptr_t)next_fp; + if (stack_grows_down) { + if (next_addr <= fp_addr) { + break; + } + } + else { + if (next_addr >= fp_addr) { + break; + } + } + frame_pointer = next_fp; + } + + return result; +} +#if defined(__GNUC__) || defined(__clang__) +static PyObject * +manual_frame_pointer_unwind(PyObject *self, PyObject *args) +{ + uintptr_t *frame_pointer = (uintptr_t *)__builtin_frame_address(0); + return manual_unwind_from_fp(frame_pointer); +} +#elif defined(MS_WINDOWS) && defined(_M_ARM64) +static PyObject * +manual_frame_pointer_unwind(PyObject *self, PyObject *args) +{ + CONTEXT ctx; + uintptr_t *frame_pointer = NULL; + + RtlCaptureContext(&ctx); + frame_pointer = (uintptr_t *)ctx.Fp; + return manual_unwind_from_fp(frame_pointer); +} +#else +static PyObject * +manual_frame_pointer_unwind(PyObject *self, PyObject *Py_UNUSED(args)) +{ + PyErr_SetString(PyExc_RuntimeError, + "manual_frame_pointer_unwind is not supported on this platform"); + return NULL; +} +#endif + static PyObject* test_bswap(PyObject *self, PyObject *Py_UNUSED(args)) { @@ -2573,6 +2843,10 @@ static PyMethodDef module_functions[] = { {"get_c_recursion_remaining", get_c_recursion_remaining, METH_NOARGS}, {"get_stack_pointer", get_stack_pointer, METH_NOARGS}, {"get_stack_margin", get_stack_margin, METH_NOARGS}, + {"classify_stack_addresses", classify_stack_addresses, METH_VARARGS}, + {"get_jit_code_ranges", get_jit_code_ranges, METH_NOARGS}, + {"get_jit_backend", get_jit_backend, METH_NOARGS}, + {"manual_frame_pointer_unwind", manual_frame_pointer_unwind, METH_NOARGS}, {"test_bswap", test_bswap, METH_NOARGS}, {"test_popcount", test_popcount, METH_NOARGS}, {"test_bit_length", test_bit_length, METH_NOARGS}, diff --git a/Python/jit.c b/Python/jit.c index 5ca9313aadf..7e47b70f1f4 100644 --- a/Python/jit.c +++ b/Python/jit.c @@ -58,6 +58,49 @@ jit_error(const char *message) PyErr_Format(PyExc_RuntimeWarning, "JIT %s (%d)", message, hint); } +static size_t _Py_jit_shim_size = 0; + +static int +address_in_executor_list(_PyExecutorObject *head, uintptr_t addr) +{ + for (_PyExecutorObject *exec = head; + exec != NULL; + exec = exec->vm_data.links.next) + { + if (exec->jit_code == NULL || exec->jit_size == 0) { + continue; + } + uintptr_t start = (uintptr_t)exec->jit_code; + uintptr_t end = start + exec->jit_size; + if (addr >= start && addr < end) { + return 1; + } + } + return 0; +} + +PyAPI_FUNC(int) +_PyJIT_AddressInJitCode(PyInterpreterState *interp, uintptr_t addr) +{ + if (interp == NULL) { + return 0; + } + if (_Py_jit_entry != _Py_LazyJitShim && _Py_jit_shim_size != 0) { + uintptr_t start = (uintptr_t)_Py_jit_entry; + uintptr_t end = start + _Py_jit_shim_size; + if (addr >= start && addr < end) { + return 1; + } + } + if (address_in_executor_list(interp->executor_list_head, addr)) { + return 1; + } + if (address_in_executor_list(interp->executor_deletion_list_head, addr)) { + return 1; + } + return 0; +} + static unsigned char * jit_alloc(size_t size) { @@ -151,8 +194,6 @@ typedef struct { uintptr_t instruction_starts[UOP_MAX_TRACE_LENGTH]; } jit_state; -static size_t _Py_jit_shim_size = 0; - // Warning! AArch64 requires you to get your hands dirty. These are your gloves: // value[value_start : value_start + len] From 6b4538192ddac518b9c15b3f79445c964330dee3 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 27 Jan 2026 16:38:50 -0500 Subject: [PATCH 093/133] gh-120321: Add missing "return false" in gen_try_set_executing (gh-144291) We didn't catch this because of a combination of: 1) falling through to the if-statement below works 2) we only specialized FOR_ITER_GEN for uniquely referenced generators, so we didn't trigger the non-thread-safe behavior. --- Python/ceval_macros.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index d791ba0e8ec..79ec8032916 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -529,6 +529,7 @@ gen_try_set_executing(PyGenObject *gen) return true; } } + return false; } #endif // Use faster non-atomic modifications in the GIL-enabled build and when From 6ea3f8cd7ff4ff9769ae276dabc0753e09dca998 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Tue, 27 Jan 2026 17:52:50 -0500 Subject: [PATCH 094/133] gh-144289: Remove ENABLE_SPECIALIZATION_FT (gh-144290) Now that the specializing interpreter works with free threading, replace ENABLE_SPECIALIZATION_FT with ENABLE_SPECIALIZATION and replace requires_specialization_ft with requires_specialization. Also limit the uniquely referenced check to FOR_ITER_RANGE. It's not necessary for FOR_ITER_GEN and would cause test_for_iter_gen to fail. --- Include/internal/pycore_code.h | 10 ---- Lib/test/support/__init__.py | 5 -- Lib/test/test_monitoring.py | 4 +- Lib/test/test_opcache.py | 72 ++++++++++++------------ Lib/test/test_thread_local_bytecode.py | 6 +- Lib/test/test_type_cache.py | 4 +- Modules/_opcode.c | 3 - Modules/_testinternalcapi/test_cases.c.h | 64 ++++++++++----------- Python/bytecodes.c | 64 ++++++++++----------- Python/ceval.c | 2 - Python/ceval_macros.h | 2 +- Python/generated_cases.c.h | 64 ++++++++++----------- Python/specialize.c | 56 +++++++++--------- 13 files changed, 167 insertions(+), 189 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index bd3f4f38e5a..efae3b38654 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -292,17 +292,7 @@ extern int _PyCode_SafeAddr2Line(PyCodeObject *co, int addr); extern void _PyCode_Clear_Executors(PyCodeObject *code); -#ifdef Py_GIL_DISABLED -// gh-115999 tracks progress on addressing this. -#define ENABLE_SPECIALIZATION 0 -// Use this to enable specialization families once they are thread-safe. All -// uses will be replaced with ENABLE_SPECIALIZATION once all families are -// thread-safe. -#define ENABLE_SPECIALIZATION_FT 1 -#else #define ENABLE_SPECIALIZATION 1 -#define ENABLE_SPECIALIZATION_FT ENABLE_SPECIALIZATION -#endif /* Specialization functions, these are exported only for other re-generated * interpreters to call */ diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 9c113a6c137..66469d088f3 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -1459,11 +1459,6 @@ def requires_specialization(test): _opcode.ENABLE_SPECIALIZATION, "requires specialization")(test) -def requires_specialization_ft(test): - return unittest.skipUnless( - _opcode.ENABLE_SPECIALIZATION_FT, "requires specialization")(test) - - def reset_code(f: types.FunctionType) -> types.FunctionType: """Clear all specializations, local instrumentation, and JIT code for the given function.""" f.__code__ = f.__code__.replace() diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 83bf510ceea..1b22e0ec875 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -12,7 +12,7 @@ import unittest import test.support -from test.support import import_helper, requires_specialization_ft, script_helper +from test.support import import_helper, requires_specialization, script_helper _testcapi = import_helper.import_module("_testcapi") _testinternalcapi = import_helper.import_module("_testinternalcapi") @@ -1047,7 +1047,7 @@ def func(): ) self.assertEqual(events[0], ("throw", IndexError)) - @requires_specialization_ft + @requires_specialization def test_no_unwind_for_shim_frame(self): class ValueErrorRaiser: def __init__(self): diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py index 56634d34366..343711ce3a9 100644 --- a/Lib/test/test_opcache.py +++ b/Lib/test/test_opcache.py @@ -5,7 +5,7 @@ import types import unittest from test.support import (threading_helper, check_impl_detail, - requires_specialization, requires_specialization_ft, + requires_specialization, cpython_only, requires_jit_disabled, reset_code) from test.support.import_helper import import_module @@ -524,7 +524,7 @@ def f(x, y): f() @requires_jit_disabled - @requires_specialization_ft + @requires_specialization def test_assign_init_code(self): class MyClass: def __init__(self): @@ -547,7 +547,7 @@ def count_args(self, *args): instantiate() @requires_jit_disabled - @requires_specialization_ft + @requires_specialization def test_push_init_frame_fails(self): def instantiate(): return InitTakesArg() @@ -576,7 +576,7 @@ def f(): f() @requires_jit_disabled - @requires_specialization_ft + @requires_specialization def test_specialize_call_function_ex_py(self): def ex_py(*args, **kwargs): return 1 @@ -592,7 +592,7 @@ def instantiate(): self.assert_specialized(instantiate, "CALL_EX_PY") @requires_jit_disabled - @requires_specialization_ft + @requires_specialization def test_specialize_call_function_ex_py_fail(self): def ex_py(*args, **kwargs): return 1 @@ -660,7 +660,7 @@ def assert_races_do_not_crash( for writer in writers: writer.join() - @requires_specialization_ft + @requires_specialization def test_binary_subscr_getitem(self): def get_items(): class C: @@ -690,7 +690,7 @@ def write(items): opname = "BINARY_OP_SUBSCR_GETITEM" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_binary_subscr_list_int(self): def get_items(): items = [] @@ -768,7 +768,7 @@ def write(items): opname = "FOR_ITER_LIST" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_class(self): def get_items(): class C: @@ -798,7 +798,7 @@ def write(items): opname = "LOAD_ATTR_CLASS" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_class_with_metaclass_check(self): def get_items(): class Meta(type): @@ -831,7 +831,7 @@ def write(items): opname = "LOAD_ATTR_CLASS_WITH_METACLASS_CHECK" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_getattribute_overridden(self): def get_items(): class C: @@ -861,7 +861,7 @@ def write(items): opname = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_instance_value(self): def get_items(): class C: @@ -885,7 +885,7 @@ def write(items): opname = "LOAD_ATTR_INSTANCE_VALUE" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_method_lazy_dict(self): def get_items(): class C(Exception): @@ -915,7 +915,7 @@ def write(items): opname = "LOAD_ATTR_METHOD_LAZY_DICT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_method_no_dict(self): def get_items(): class C: @@ -946,7 +946,7 @@ def write(items): opname = "LOAD_ATTR_METHOD_NO_DICT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_method_with_values(self): def get_items(): class C: @@ -976,7 +976,7 @@ def write(items): opname = "LOAD_ATTR_METHOD_WITH_VALUES" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_module(self): def get_items(): items = [] @@ -1001,7 +1001,7 @@ def write(items): opname = "LOAD_ATTR_MODULE" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_property(self): def get_items(): class C: @@ -1031,7 +1031,7 @@ def write(items): opname = "LOAD_ATTR_PROPERTY" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_slot(self): def get_items(): class C: @@ -1058,7 +1058,7 @@ def write(items): opname = "LOAD_ATTR_SLOT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_attr_with_hint(self): def get_items(): class C: @@ -1085,7 +1085,7 @@ def write(items): opname = "LOAD_ATTR_WITH_HINT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_load_global_module(self): if not have_dict_key_versions(): raise unittest.SkipTest("Low on dict key versions") @@ -1158,7 +1158,7 @@ def write(items): opname = "STORE_ATTR_WITH_HINT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_store_subscr_list_int(self): def get_items(): items = [] @@ -1182,7 +1182,7 @@ def write(items): opname = "STORE_SUBSCR_LIST_INT" self.assert_races_do_not_crash(opname, get_items, read, write) - @requires_specialization_ft + @requires_specialization def test_unpack_sequence_list(self): def get_items(): items = [] @@ -1362,7 +1362,7 @@ def f(o, n): class TestSpecializer(TestBase): @cpython_only - @requires_specialization_ft + @requires_specialization def test_binary_op(self): def binary_op_add_int(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): @@ -1497,7 +1497,7 @@ def binary_op_bitwise_extend(): self.assert_no_opcode(binary_op_bitwise_extend, "BINARY_OP") @cpython_only - @requires_specialization_ft + @requires_specialization def test_load_super_attr(self): """Ensure that LOAD_SUPER_ATTR is specialized as expected.""" @@ -1536,7 +1536,7 @@ def init(self): self.assert_no_opcode(A.__init__, "LOAD_SUPER_ATTR_METHOD") @cpython_only - @requires_specialization_ft + @requires_specialization def test_contain_op(self): def contains_op_dict(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): @@ -1559,7 +1559,7 @@ def contains_op_set(): self.assert_no_opcode(contains_op_set, "CONTAINS_OP") @cpython_only - @requires_specialization_ft + @requires_specialization def test_send_with(self): def run_async(coro): while True: @@ -1586,7 +1586,7 @@ async def send_with(): self.assert_specialized(send_with, "SEND_GEN") @cpython_only - @requires_specialization_ft + @requires_specialization def test_send_yield_from(self): def g(): yield None @@ -1601,7 +1601,7 @@ def send_yield_from(): self.assert_no_opcode(send_yield_from, "SEND") @cpython_only - @requires_specialization_ft + @requires_specialization def test_store_attr_slot(self): class C: __slots__ = ['x'] @@ -1622,7 +1622,7 @@ def set_slot(n): self.assert_no_opcode(set_slot, "STORE_ATTR_SLOT") @cpython_only - @requires_specialization_ft + @requires_specialization def test_store_attr_instance_value(self): class C: pass @@ -1644,7 +1644,7 @@ def set_value(n): self.assert_no_opcode(set_value, "STORE_ATTR_INSTANCE_VALUE") @cpython_only - @requires_specialization_ft + @requires_specialization def test_store_attr_with_hint(self): class C: pass @@ -1669,7 +1669,7 @@ def set_value(n): self.assert_no_opcode(set_value, "STORE_ATTR_WITH_HINT") @cpython_only - @requires_specialization_ft + @requires_specialization def test_to_bool(self): def to_bool_bool(): true_cnt, false_cnt = 0, 0 @@ -1737,7 +1737,7 @@ def to_bool_str(): self.assert_no_opcode(to_bool_str, "TO_BOOL") @cpython_only - @requires_specialization_ft + @requires_specialization def test_unpack_sequence(self): def unpack_sequence_two_tuple(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): @@ -1774,7 +1774,7 @@ def unpack_sequence_list(): self.assert_no_opcode(unpack_sequence_list, "UNPACK_SEQUENCE") @cpython_only - @requires_specialization_ft + @requires_specialization def test_binary_subscr(self): def binary_subscr_list_int(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): @@ -1844,7 +1844,7 @@ def __getitem__(self, item): self.assert_no_opcode(binary_subscr_getitems, "BINARY_OP") @cpython_only - @requires_specialization_ft + @requires_specialization def test_compare_op(self): def compare_op_int(): for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD): @@ -1878,7 +1878,7 @@ def compare_op_str(): @cpython_only - @requires_specialization_ft + @requires_specialization def test_for_iter(self): L = list(range(10)) def for_iter_list(): @@ -1916,7 +1916,7 @@ def for_iter_generator(): self.assert_no_opcode(for_iter_generator, "FOR_ITER") @cpython_only - @requires_specialization_ft + @requires_specialization def test_call_list_append(self): # gh-141367: only exact lists should use # CALL_LIST_APPEND instruction after specialization. @@ -1943,7 +1943,7 @@ class MyList(list): pass self.assert_no_opcode(my_list_append, "CALL") @cpython_only - @requires_specialization_ft + @requires_specialization def test_load_attr_module_with_getattr(self): module = types.ModuleType("test_module_with_getattr") module.__dict__["some_attr"] = "foo" diff --git a/Lib/test/test_thread_local_bytecode.py b/Lib/test/test_thread_local_bytecode.py index d5c56db8d5d..6a1ae4064b5 100644 --- a/Lib/test/test_thread_local_bytecode.py +++ b/Lib/test/test_thread_local_bytecode.py @@ -3,7 +3,7 @@ import unittest from test import support -from test.support import cpython_only, import_helper, requires_specialization_ft +from test.support import cpython_only, import_helper, requires_specialization from test.support.script_helper import assert_python_ok from test.support.threading_helper import requires_working_threading @@ -15,7 +15,7 @@ @requires_working_threading() @unittest.skipUnless(support.Py_GIL_DISABLED, "only in free-threaded builds") class TLBCTests(unittest.TestCase): - @requires_specialization_ft + @requires_specialization def test_new_threads_start_with_unspecialized_code(self): code = textwrap.dedent(""" import dis @@ -46,7 +46,7 @@ def f(a, b, q=None): """) assert_python_ok("-X", "tlbc=1", "-c", code) - @requires_specialization_ft + @requires_specialization def test_threads_specialize_independently(self): code = textwrap.dedent(""" import dis diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py index 7469a1047f8..22ad9f6243e 100644 --- a/Lib/test/test_type_cache.py +++ b/Lib/test/test_type_cache.py @@ -3,7 +3,7 @@ import unittest import warnings from test import support -from test.support import import_helper, requires_specialization, requires_specialization_ft +from test.support import import_helper, requires_specialization try: from sys import _clear_type_cache except ImportError: @@ -219,7 +219,7 @@ def store_bar_2(type_): self._check_specialization(store_bar_2, B(), "STORE_ATTR", should_specialize=False) - @requires_specialization_ft + @requires_specialization def test_class_call_specialization_user_type(self): class F: def __init__(self): diff --git a/Modules/_opcode.c b/Modules/_opcode.c index ef271b6ef56..2fe09593a45 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -423,9 +423,6 @@ _opcode_exec(PyObject *m) { if (PyModule_AddIntMacro(m, ENABLE_SPECIALIZATION) < 0) { return -1; } - if (PyModule_AddIntMacro(m, ENABLE_SPECIALIZATION_FT) < 0) { - return -1; - } return 0; } diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index d46af254a41..f4373a753ed 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -41,7 +41,7 @@ lhs = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -51,7 +51,7 @@ } OPCODE_DEFERRED_INC(BINARY_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ assert(NB_ADD <= oparg); assert(oparg <= NB_OPARG_LAST); } @@ -1742,7 +1742,7 @@ callable = stack_pointer[-2 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1752,7 +1752,7 @@ } OPCODE_DEFERRED_INC(CALL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _MAYBE_EXPAND_METHOD @@ -2783,7 +2783,7 @@ func = stack_pointer[-4]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -2793,7 +2793,7 @@ } OPCODE_DEFERRED_INC(CALL_FUNCTION_EX); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _MAKE_CALLARGS_A_TUPLE { @@ -3111,7 +3111,7 @@ callable = stack_pointer[-3 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3121,7 +3121,7 @@ } OPCODE_DEFERRED_INC(CALL_KW); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _MAYBE_EXPAND_METHOD_KW @@ -4771,7 +4771,7 @@ left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4781,7 +4781,7 @@ } OPCODE_DEFERRED_INC(COMPARE_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _COMPARE_OP { @@ -5061,7 +5061,7 @@ right = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -5071,7 +5071,7 @@ } OPCODE_DEFERRED_INC(CONTAINS_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _CONTAINS_OP { @@ -5815,7 +5815,7 @@ iter = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -5825,7 +5825,7 @@ } OPCODE_DEFERRED_INC(FOR_ITER); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _FOR_ITER { @@ -7880,7 +7880,7 @@ owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -7891,7 +7891,7 @@ } OPCODE_DEFERRED_INC(LOAD_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 8 cache entries */ // _LOAD_ATTR @@ -9215,7 +9215,7 @@ { uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -9226,7 +9226,7 @@ } OPCODE_DEFERRED_INC(LOAD_GLOBAL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 1 cache entry */ /* Skip 1 cache entry */ @@ -9535,7 +9535,7 @@ global_super_st = stack_pointer[-3]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION int load_method = oparg & 1; if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; @@ -9546,7 +9546,7 @@ } OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _LOAD_SUPER_ATTR { @@ -10381,11 +10381,11 @@ } // _QUICKEN_RESUME { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (tstate->tracing == 0 && this_instr->op.code == RESUME) { FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); } - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _CHECK_PERIODIC_IF_NOT_YIELD_FROM { @@ -10529,7 +10529,7 @@ receiver = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -10539,7 +10539,7 @@ } OPCODE_DEFERRED_INC(SEND); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _SEND { @@ -10825,7 +10825,7 @@ owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr = this_instr; @@ -10836,7 +10836,7 @@ } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 3 cache entries */ // _STORE_ATTR @@ -11365,7 +11365,7 @@ container = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -11375,7 +11375,7 @@ } OPCODE_DEFERRED_INC(STORE_SUBSCR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _STORE_SUBSCR { @@ -11604,7 +11604,7 @@ value = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -11614,7 +11614,7 @@ } OPCODE_DEFERRED_INC(TO_BOOL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _TO_BOOL @@ -12059,7 +12059,7 @@ seq = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -12069,7 +12069,7 @@ } OPCODE_DEFERRED_INC(UNPACK_SEQUENCE); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ (void)seq; (void)counter; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index edda90b5fb3..4c808016a00 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -169,11 +169,11 @@ dummy_func( } op(_QUICKEN_RESUME, (--)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (tstate->tracing == 0 && this_instr->op.code == RESUME) { FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); } - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } tier1 op(_MAYBE_INSTRUMENT, (--)) { @@ -463,7 +463,7 @@ dummy_func( }; specializing op(_SPECIALIZE_TO_BOOL, (counter/1, value -- value)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_ToBool(value, next_instr); @@ -471,7 +471,7 @@ dummy_func( } OPCODE_DEFERRED_INC(TO_BOOL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_TO_BOOL, (value -- res)) { @@ -1131,7 +1131,7 @@ dummy_func( }; specializing op(_SPECIALIZE_STORE_SUBSCR, (counter/1, container, sub -- container, sub)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_StoreSubscr(container, sub, next_instr); @@ -1139,7 +1139,7 @@ dummy_func( } OPCODE_DEFERRED_INC(STORE_SUBSCR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_STORE_SUBSCR, (v, container, sub -- )) { @@ -1351,7 +1351,7 @@ dummy_func( }; specializing op(_SPECIALIZE_SEND, (counter/1, receiver, unused -- receiver, unused)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_Send(receiver, next_instr); @@ -1359,7 +1359,7 @@ dummy_func( } OPCODE_DEFERRED_INC(SEND); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_SEND, (receiver, v -- receiver, retval)) { @@ -1620,7 +1620,7 @@ dummy_func( }; specializing op(_SPECIALIZE_UNPACK_SEQUENCE, (counter/1, seq -- seq)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); @@ -1628,7 +1628,7 @@ dummy_func( } OPCODE_DEFERRED_INC(UNPACK_SEQUENCE); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ (void)seq; (void)counter; } @@ -1705,7 +1705,7 @@ dummy_func( }; specializing op(_SPECIALIZE_STORE_ATTR, (counter/1, owner -- owner)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr = this_instr; @@ -1714,7 +1714,7 @@ dummy_func( } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_STORE_ATTR, (v, owner --)) { @@ -1823,7 +1823,7 @@ dummy_func( }; specializing op(_SPECIALIZE_LOAD_GLOBAL, (counter/1 -- )) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -1832,7 +1832,7 @@ dummy_func( } OPCODE_DEFERRED_INC(LOAD_GLOBAL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // res[1] because we need a pointer to res to pass it to _PyEval_LoadGlobalStackRef @@ -2213,7 +2213,7 @@ dummy_func( }; specializing op(_SPECIALIZE_LOAD_SUPER_ATTR, (counter/1, global_super_st, class_st, unused -- global_super_st, class_st, unused)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION int load_method = oparg & 1; if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; @@ -2222,7 +2222,7 @@ dummy_func( } OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } tier1 op(_LOAD_SUPER_ATTR, (global_super_st, class_st, self_st -- attr)) { @@ -2345,7 +2345,7 @@ dummy_func( }; specializing op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -2354,7 +2354,7 @@ dummy_func( } OPCODE_DEFERRED_INC(LOAD_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_LOAD_ATTR, (owner -- attr, self_or_null[oparg&1])) { @@ -2746,7 +2746,7 @@ dummy_func( }; specializing op(_SPECIALIZE_COMPARE_OP, (counter/1, left, right -- left, right)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_CompareOp(left, right, next_instr, oparg); @@ -2754,7 +2754,7 @@ dummy_func( } OPCODE_DEFERRED_INC(COMPARE_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_COMPARE_OP, (left, right -- res)) { @@ -2875,7 +2875,7 @@ dummy_func( } specializing op(_SPECIALIZE_CONTAINS_OP, (counter/1, left, right -- left, right)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_ContainsOp(right, next_instr); @@ -2883,7 +2883,7 @@ dummy_func( } OPCODE_DEFERRED_INC(CONTAINS_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } macro(CONTAINS_OP) = _SPECIALIZE_CONTAINS_OP + _CONTAINS_OP + POP_TOP + POP_TOP; @@ -3259,7 +3259,7 @@ dummy_func( }; specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter, null_or_index -- iter, null_or_index)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_ForIter(iter, null_or_index, next_instr, oparg); @@ -3267,7 +3267,7 @@ dummy_func( } OPCODE_DEFERRED_INC(FOR_ITER); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) { @@ -3742,7 +3742,7 @@ dummy_func( }; specializing op(_SPECIALIZE_CALL, (counter/1, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_Call(callable, self_or_null, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); @@ -3750,7 +3750,7 @@ dummy_func( } OPCODE_DEFERRED_INC(CALL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } op(_MAYBE_EXPAND_METHOD, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { @@ -4758,7 +4758,7 @@ dummy_func( _PUSH_FRAME; specializing op(_SPECIALIZE_CALL_KW, (counter/1, callable, self_or_null, unused[oparg], unused -- callable, self_or_null, unused[oparg], unused)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_CallKw(callable, next_instr, oparg + !PyStackRef_IsNull(self_or_null)); @@ -4766,7 +4766,7 @@ dummy_func( } OPCODE_DEFERRED_INC(CALL_KW); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } macro(CALL_KW) = @@ -4921,7 +4921,7 @@ dummy_func( } specializing op(_SPECIALIZE_CALL_FUNCTION_EX, (counter/1, func, unused, unused, unused -- func, unused, unused, unused)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_CallFunctionEx(func, next_instr); @@ -4929,7 +4929,7 @@ dummy_func( } OPCODE_DEFERRED_INC(CALL_FUNCTION_EX); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } macro(CALL_FUNCTION_EX) = @@ -5108,7 +5108,7 @@ dummy_func( } specializing op(_SPECIALIZE_BINARY_OP, (counter/1, lhs, rhs -- lhs, rhs)) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, LOCALS_ARRAY); @@ -5116,7 +5116,7 @@ dummy_func( } OPCODE_DEFERRED_INC(BINARY_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ assert(NB_ADD <= oparg); assert(oparg <= NB_OPARG_LAST); } diff --git a/Python/ceval.c b/Python/ceval.c index bdf1e9bb742..04ae7b4d86f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1321,8 +1321,6 @@ _PyTier2Interpreter( #undef ENABLE_SPECIALIZATION #define ENABLE_SPECIALIZATION 0 -#undef ENABLE_SPECIALIZATION_FT -#define ENABLE_SPECIALIZATION_FT 0 uint16_t uopcode; #ifdef Py_STATS diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 79ec8032916..1cbeb18d02c 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -351,7 +351,7 @@ GETITEM(PyObject *v, Py_ssize_t i) { (COUNTER) = pause_backoff_counter((COUNTER)); \ } while (0); -#ifdef ENABLE_SPECIALIZATION_FT +#ifdef ENABLE_SPECIALIZATION /* Multiple threads may execute these concurrently if thread-local bytecode is * disabled and they all execute the main copy of the bytecode. Specialization * is disabled in that case so the value is unused, but the RMW cycle should be diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 16349766d62..77d9b182ada 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -41,7 +41,7 @@ lhs = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -51,7 +51,7 @@ } OPCODE_DEFERRED_INC(BINARY_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ assert(NB_ADD <= oparg); assert(oparg <= NB_OPARG_LAST); } @@ -1742,7 +1742,7 @@ callable = stack_pointer[-2 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -1752,7 +1752,7 @@ } OPCODE_DEFERRED_INC(CALL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _MAYBE_EXPAND_METHOD @@ -2783,7 +2783,7 @@ func = stack_pointer[-4]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -2793,7 +2793,7 @@ } OPCODE_DEFERRED_INC(CALL_FUNCTION_EX); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _MAKE_CALLARGS_A_TUPLE { @@ -3111,7 +3111,7 @@ callable = stack_pointer[-3 - oparg]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3121,7 +3121,7 @@ } OPCODE_DEFERRED_INC(CALL_KW); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _MAYBE_EXPAND_METHOD_KW @@ -4771,7 +4771,7 @@ left = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -4781,7 +4781,7 @@ } OPCODE_DEFERRED_INC(COMPARE_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _COMPARE_OP { @@ -5061,7 +5061,7 @@ right = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -5071,7 +5071,7 @@ } OPCODE_DEFERRED_INC(CONTAINS_OP); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _CONTAINS_OP { @@ -5815,7 +5815,7 @@ iter = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -5825,7 +5825,7 @@ } OPCODE_DEFERRED_INC(FOR_ITER); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _FOR_ITER { @@ -7879,7 +7879,7 @@ owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -7890,7 +7890,7 @@ } OPCODE_DEFERRED_INC(LOAD_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 8 cache entries */ // _LOAD_ATTR @@ -9213,7 +9213,7 @@ { uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1); next_instr = this_instr; @@ -9224,7 +9224,7 @@ } OPCODE_DEFERRED_INC(LOAD_GLOBAL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 1 cache entry */ /* Skip 1 cache entry */ @@ -9533,7 +9533,7 @@ global_super_st = stack_pointer[-3]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION int load_method = oparg & 1; if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; @@ -9544,7 +9544,7 @@ } OPCODE_DEFERRED_INC(LOAD_SUPER_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _LOAD_SUPER_ATTR { @@ -10379,11 +10379,11 @@ } // _QUICKEN_RESUME { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (tstate->tracing == 0 && this_instr->op.code == RESUME) { FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); } - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _CHECK_PERIODIC_IF_NOT_YIELD_FROM { @@ -10526,7 +10526,7 @@ receiver = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -10536,7 +10536,7 @@ } OPCODE_DEFERRED_INC(SEND); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _SEND { @@ -10822,7 +10822,7 @@ owner = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { PyObject *name = GETITEM(FRAME_CO_NAMES, oparg); next_instr = this_instr; @@ -10833,7 +10833,7 @@ } OPCODE_DEFERRED_INC(STORE_ATTR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 3 cache entries */ // _STORE_ATTR @@ -11362,7 +11362,7 @@ container = stack_pointer[-2]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -11372,7 +11372,7 @@ } OPCODE_DEFERRED_INC(STORE_SUBSCR); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } // _STORE_SUBSCR { @@ -11601,7 +11601,7 @@ value = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -11611,7 +11611,7 @@ } OPCODE_DEFERRED_INC(TO_BOOL); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } /* Skip 2 cache entries */ // _TO_BOOL @@ -12056,7 +12056,7 @@ seq = stack_pointer[-1]; uint16_t counter = read_u16(&this_instr[1].cache); (void)counter; - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION if (ADAPTIVE_COUNTER_TRIGGERS(counter)) { next_instr = this_instr; _PyFrame_SetStackPointer(frame, stack_pointer); @@ -12066,7 +12066,7 @@ } OPCODE_DEFERRED_INC(UNPACK_SEQUENCE); ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter); - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ (void)seq; (void)counter; } diff --git a/Python/specialize.c b/Python/specialize.c index 845416a1d5b..21e0eb802dd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -44,7 +44,7 @@ do { \ void _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters) { - #if ENABLE_SPECIALIZATION_FT + #if ENABLE_SPECIALIZATION _Py_BackoffCounter jump_counter, adaptive_counter; if (enable_counters) { PyThreadState *tstate = _PyThreadState_GET(); @@ -85,7 +85,7 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters oparg = 0; } } - #endif /* ENABLE_SPECIALIZATION_FT */ + #endif /* ENABLE_SPECIALIZATION */ } #define SIMPLE_FUNCTION 0 @@ -431,7 +431,7 @@ _Py_Specialize_LoadSuperAttr(_PyStackRef global_super_st, _PyStackRef cls_st, _P PyObject *global_super = PyStackRef_AsPyObjectBorrow(global_super_st); PyObject *cls = PyStackRef_AsPyObjectBorrow(cls_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_SUPER_ATTR] == INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR); if (global_super != (PyObject *)&PySuper_Type) { SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_SHADOWED); @@ -952,7 +952,7 @@ _Py_Specialize_LoadAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *nam { PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_ATTR] == INLINE_CACHE_ENTRIES_LOAD_ATTR); PyTypeObject *type = Py_TYPE(owner); bool fail; @@ -983,7 +983,7 @@ _Py_Specialize_StoreAttr(_PyStackRef owner_st, _Py_CODEUNIT *instr, PyObject *na { PyObject *owner = PyStackRef_AsPyObjectBorrow(owner_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[STORE_ATTR] == INLINE_CACHE_ENTRIES_STORE_ATTR); PyObject *descr = NULL; _PyAttrCache *cache = (_PyAttrCache *)(instr + 1); @@ -1293,7 +1293,7 @@ specialize_load_global_lock_held( PyObject *globals, PyObject *builtins, _Py_CODEUNIT *instr, PyObject *name) { - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[LOAD_GLOBAL] == INLINE_CACHE_ENTRIES_LOAD_GLOBAL); /* Use inline cache */ _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)(instr + 1); @@ -1514,7 +1514,7 @@ _Py_Specialize_StoreSubscr(_PyStackRef container_st, _PyStackRef sub_st, _Py_COD PyObject *container = PyStackRef_AsPyObjectBorrow(container_st); PyObject *sub = PyStackRef_AsPyObjectBorrow(sub_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); PyTypeObject *container_type = Py_TYPE(container); if (container_type == &PyList_Type) { if (PyLong_CheckExact(sub)) { @@ -1802,7 +1802,7 @@ _Py_Specialize_Call(_PyStackRef callable_st, _PyStackRef self_or_null_st, _Py_CO { PyObject *callable = PyStackRef_AsPyObjectBorrow(callable_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL); assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL); int fail; @@ -1844,7 +1844,7 @@ _Py_Specialize_CallKw(_PyStackRef callable_st, _Py_CODEUNIT *instr, int nargs) { PyObject *callable = PyStackRef_AsPyObjectBorrow(callable_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL_KW] == INLINE_CACHE_ENTRIES_CALL_KW); assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL_KW); int fail; @@ -2200,7 +2200,7 @@ _Py_Specialize_BinaryOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *in { PyObject *lhs = PyStackRef_AsPyObjectBorrow(lhs_st); PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[BINARY_OP] == INLINE_CACHE_ENTRIES_BINARY_OP); _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(instr + 1); @@ -2369,7 +2369,7 @@ _Py_Specialize_CompareOp(_PyStackRef lhs_st, _PyStackRef rhs_st, _Py_CODEUNIT *i PyObject *rhs = PyStackRef_AsPyObjectBorrow(rhs_st); uint8_t specialized_op; - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[COMPARE_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); // All of these specializations compute boolean values, so they're all valid // regardless of the fifth-lowest oparg bit. @@ -2429,7 +2429,7 @@ _Py_Specialize_UnpackSequence(_PyStackRef seq_st, _Py_CODEUNIT *instr, int oparg { PyObject *seq = PyStackRef_AsPyObjectBorrow(seq_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[UNPACK_SEQUENCE] == INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); if (PyTuple_CheckExact(seq)) { @@ -2534,29 +2534,27 @@ int Py_NO_INLINE void _Py_Specialize_ForIter(_PyStackRef iter, _PyStackRef null_or_index, _Py_CODEUNIT *instr, int oparg) { - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[FOR_ITER] == INLINE_CACHE_ENTRIES_FOR_ITER); PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); PyTypeObject *tp = Py_TYPE(iter_o); if (PyStackRef_IsNull(null_or_index)) { -#ifdef Py_GIL_DISABLED - // Only specialize for uniquely referenced iterators, so that we know - // they're only referenced by this one thread. This is more limiting - // than we need (even `it = iter(mylist); for item in it:` won't get - // specialized) but we don't have a way to check whether we're the only - // _thread_ who has access to the object. - if (!_PyObject_IsUniquelyReferenced(iter_o)) { - goto failure; - } -#endif if (tp == &PyRangeIter_Type) { +#ifdef Py_GIL_DISABLED + // Only specialize for uniquely referenced iterators, so that we know + // they're only referenced by this one thread. This is more limiting + // than we need (even `it = iter(mylist); for item in it:` won't get + // specialized) but we don't have a way to check whether we're the only + // _thread_ who has access to the object. + if (!_PyObject_IsUniquelyReferenced(iter_o)) { + goto failure; + } +#endif specialize(instr, FOR_ITER_RANGE); return; } else if (tp == &PyGen_Type && oparg <= SHRT_MAX) { - // Generators are very much not thread-safe, so don't worry about - // the specialization not being thread-safe. assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR || instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR ); @@ -2595,7 +2593,7 @@ _Py_Specialize_Send(_PyStackRef receiver_st, _Py_CODEUNIT *instr) { PyObject *receiver = PyStackRef_AsPyObjectBorrow(receiver_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[SEND] == INLINE_CACHE_ENTRIES_SEND); PyTypeObject *tp = Py_TYPE(receiver); if (tp == &PyGen_Type || tp == &PyCoro_Type) { @@ -2618,7 +2616,7 @@ _Py_Specialize_CallFunctionEx(_PyStackRef func_st, _Py_CODEUNIT *instr) { PyObject *func = PyStackRef_AsPyObjectBorrow(func_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL_FUNCTION_EX] == INLINE_CACHE_ENTRIES_CALL_FUNCTION_EX); if (Py_TYPE(func) == &PyFunction_Type && @@ -2685,7 +2683,7 @@ check_type_always_true(PyTypeObject *ty) Py_NO_INLINE void _Py_Specialize_ToBool(_PyStackRef value_o, _Py_CODEUNIT *instr) { - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[TO_BOOL] == INLINE_CACHE_ENTRIES_TO_BOOL); _PyToBoolCache *cache = (_PyToBoolCache *)(instr + 1); PyObject *value = PyStackRef_AsPyObjectBorrow(value_o); @@ -2761,7 +2759,7 @@ _Py_Specialize_ContainsOp(_PyStackRef value_st, _Py_CODEUNIT *instr) { PyObject *value = PyStackRef_AsPyObjectBorrow(value_st); - assert(ENABLE_SPECIALIZATION_FT); + assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CONTAINS_OP] == INLINE_CACHE_ENTRIES_COMPARE_OP); if (PyDict_CheckExact(value)) { specialize(instr, CONTAINS_OP_DICT); From 1a637b29aa1d1e96a5be14f520160caf04e8ee16 Mon Sep 17 00:00:00 2001 From: Romuald Brunet Date: Wed, 28 Jan 2026 11:20:51 +0100 Subject: [PATCH 095/133] gh-144249: Report filename in SSLContext.load_cert_chain errors (#144250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When user tries to load a certificate chain, attach the related filename to the exception being raised. Improving user experience. Co-authored-by: Victor Stinner Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_ssl.py | 6 ++++++ .../Library/2026-01-27-09-58-52.gh-issue-144249.mCIy95.rst | 2 ++ Modules/_ssl.c | 6 ++++-- 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-27-09-58-52.gh-issue-144249.mCIy95.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 9dc99fbf5cf..6023c89bca0 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -131,6 +131,7 @@ def data_file(*name): EMPTYCERT = data_file("nullcert.pem") BADCERT = data_file("badcert.pem") NONEXISTINGCERT = data_file("XXXnonexisting.pem") +NONEXISTINGKEY = data_file("XXXnonexistingkey.pem") BADKEY = data_file("badkey.pem") NOKIACERT = data_file("nokia.pem") NULLBYTECERT = data_file("nullbytecert.pem") @@ -1229,6 +1230,11 @@ def test_load_cert_chain(self): with self.assertRaises(OSError) as cm: ctx.load_cert_chain(NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(cm.exception.filename, NONEXISTINGCERT) + with self.assertRaises(OSError) as cm: + ctx.load_cert_chain(CERTFILE, keyfile=NONEXISTINGKEY) + self.assertEqual(cm.exception.errno, errno.ENOENT) + self.assertEqual(cm.exception.filename, NONEXISTINGKEY) with self.assertRaisesRegex(ssl.SSLError, "PEM (lib|routines)"): ctx.load_cert_chain(BADCERT) with self.assertRaisesRegex(ssl.SSLError, "PEM (lib|routines)"): diff --git a/Misc/NEWS.d/next/Library/2026-01-27-09-58-52.gh-issue-144249.mCIy95.rst b/Misc/NEWS.d/next/Library/2026-01-27-09-58-52.gh-issue-144249.mCIy95.rst new file mode 100644 index 00000000000..52f27cec478 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-27-09-58-52.gh-issue-144249.mCIy95.rst @@ -0,0 +1,2 @@ +Add filename context to :exc:`OSError` exceptions raised by +:func:`ssl.SSLContext.load_cert_chain`, allowing users to have more context. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 22865bdfc3f..66d699b4339 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4517,7 +4517,8 @@ load_cert_chain_lock_held(PySSLContext *self, _PySSLPasswordInfo *pw_info, /* the password callback has already set the error information */ } else if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); + PyErr_SetFromErrnoWithFilename(PyExc_OSError, + PyBytes_AS_STRING(certfile_bytes)); ERR_clear_error(); } else { @@ -4537,7 +4538,8 @@ load_cert_chain_lock_held(PySSLContext *self, _PySSLPasswordInfo *pw_info, /* the password callback has already set the error information */ } else if (errno != 0) { - PyErr_SetFromErrno(PyExc_OSError); + PyErr_SetFromErrnoWithFilename(PyExc_OSError, + PyBytes_AS_STRING(keyfile_bytes ? keyfile_bytes : certfile_bytes)); ERR_clear_error(); } else { From 08d7bd28fecca524c648dda240022add704b8f8a Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 28 Jan 2026 11:27:37 +0100 Subject: [PATCH 096/133] gh-140232: Do not track frozenset objects with immutables (#140234) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Mikhail Efimov Co-authored-by: Victor Stinner --- Lib/test/test_capi/test_set.py | 6 ++ Lib/test/test_sys.py | 5 +- ...-10-16-22-36-05.gh-issue-140232.u3srgv.rst | 1 + Modules/_testlimitedcapi/set.c | 68 +++++++++++++++++++ Objects/setobject.c | 37 +++++++++- 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-10-16-22-36-05.gh-issue-140232.u3srgv.rst diff --git a/Lib/test/test_capi/test_set.py b/Lib/test/test_capi/test_set.py index 62d90a3f943..a41c2fcaf12 100644 --- a/Lib/test/test_capi/test_set.py +++ b/Lib/test/test_capi/test_set.py @@ -166,6 +166,12 @@ def test_add(self): # CRASHES: add(instance, NULL) # CRASHES: add(NULL, NULL) + def test_add_frozenset(self): + add = _testlimitedcapi.set_add + frozen_set = frozenset() + # test adding an element to a non-uniquely referenced frozenset throws an exception + self.assertRaises(SystemError, add, frozen_set, 1) + def test_discard(self): discard = _testlimitedcapi.set_discard for cls in (set, set_subclass): diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index a5708b298c8..b44e0c9779a 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1880,7 +1880,10 @@ class S(set): check(S(), set(), '3P') class FS(frozenset): __slots__ = 'a', 'b', 'c' - check(FS(), frozenset(), '3P') + + class mytuple(tuple): + pass + check(FS([mytuple()]), frozenset([mytuple()]), '3P') from collections import OrderedDict class OD(OrderedDict): __slots__ = 'a', 'b', 'c' diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-16-22-36-05.gh-issue-140232.u3srgv.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-16-22-36-05.gh-issue-140232.u3srgv.rst new file mode 100644 index 00000000000..e40daacbc45 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-16-22-36-05.gh-issue-140232.u3srgv.rst @@ -0,0 +1 @@ +Frozenset objects with immutable elements are no longer tracked by the garbage collector. diff --git a/Modules/_testlimitedcapi/set.c b/Modules/_testlimitedcapi/set.c index 34ed6b1d60b..8aade9502b6 100644 --- a/Modules/_testlimitedcapi/set.c +++ b/Modules/_testlimitedcapi/set.c @@ -155,6 +155,72 @@ test_frozenset_add_in_capi(PyObject *self, PyObject *Py_UNUSED(obj)) return NULL; } +static PyObject * +raiseTestError(const char* test_name, const char* msg) +{ + PyErr_Format(PyExc_AssertionError, "%s: %s", test_name, msg); + return NULL; +} + +static PyObject * +test_frozenset_add_in_capi_tracking_immutable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + // Test: GC tracking - frozenset with only immutable items should not be tracked + PyObject *frozenset = PyFrozenSet_New(NULL); + if (frozenset == NULL) { + return NULL; + } + if (PySet_Add(frozenset, Py_True) < 0) { + Py_DECREF(frozenset); + return NULL; + } + if (PyObject_GC_IsTracked(frozenset)) { + Py_DECREF(frozenset); + return raiseTestError("test_frozenset_add_in_capi_tracking_immutable", + "frozenset with only bool should not be GC tracked"); + } + Py_DECREF(frozenset); + Py_RETURN_NONE; +} + +static PyObject * +test_frozenset_add_in_capi_tracking(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + // Test: GC tracking - frozenset with tracked object should be tracked + PyObject *frozenset = PyFrozenSet_New(NULL); + if (frozenset == NULL) { + return NULL; + } + + PyObject *tracked_obj = PyErr_NewException("_testlimitedcapi.py_set_add", NULL, NULL); + if (tracked_obj == NULL) { + goto error; + } + if (!PyObject_GC_IsTracked(tracked_obj)) { + Py_DECREF(frozenset); + Py_DECREF(tracked_obj); + return raiseTestError("test_frozenset_add_in_capi_tracking", + "test object should be tracked"); + } + if (PySet_Add(frozenset, tracked_obj) < 0) { + goto error; + } + Py_DECREF(tracked_obj); + if (!PyObject_GC_IsTracked(frozenset)) { + Py_DECREF(frozenset); + return raiseTestError("test_frozenset_add_in_capi_tracking", + "frozenset with with GC tracked object should be tracked"); + } + Py_DECREF(frozenset); + Py_RETURN_NONE; + +error: + Py_DECREF(frozenset); + Py_XDECREF(tracked_obj); + return NULL; +} + + static PyObject * test_set_contains_does_not_convert_unhashable_key(PyObject *self, PyObject *Py_UNUSED(obj)) { @@ -219,6 +285,8 @@ static PyMethodDef test_methods[] = { {"set_clear", set_clear, METH_O}, {"test_frozenset_add_in_capi", test_frozenset_add_in_capi, METH_NOARGS}, + {"test_frozenset_add_in_capi_tracking", test_frozenset_add_in_capi_tracking, METH_NOARGS}, + {"test_frozenset_add_in_capi_tracking_immutable", test_frozenset_add_in_capi_tracking_immutable, METH_NOARGS}, {"test_set_contains_does_not_convert_unhashable_key", test_set_contains_does_not_convert_unhashable_key, METH_NOARGS}, diff --git a/Objects/setobject.c b/Objects/setobject.c index 378f221bcfd..5d4d1812282 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1368,6 +1368,26 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } +// gh-140232: check whether a frozenset can be untracked from the GC +static void +_PyFrozenSet_MaybeUntrack(PyObject *op) +{ + assert(op != NULL); + // subclasses of a frozenset can generate reference cycles, so do not untrack + if (!PyFrozenSet_CheckExact(op)) { + return; + } + // if no elements of a frozenset are tracked by the GC, we untrack the object + Py_ssize_t pos = 0; + setentry *entry; + while (set_next((PySetObject *)op, &pos, &entry)) { + if (_PyObject_GC_MAY_BE_TRACKED(entry->key)) { + return; + } + } + _PyObject_GC_UNTRACK(op); +} + static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { @@ -1379,7 +1399,11 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) /* frozenset(f) is idempotent */ return Py_NewRef(iterable); } - return make_new_set(type, iterable); + PyObject *obj = make_new_set(type, iterable); + if (obj != NULL) { + _PyFrozenSet_MaybeUntrack(obj); + } + return obj; } static PyObject * @@ -2932,7 +2956,11 @@ PySet_New(PyObject *iterable) PyObject * PyFrozenSet_New(PyObject *iterable) { - return make_new_set(&PyFrozenSet_Type, iterable); + PyObject *result = make_new_set(&PyFrozenSet_Type, iterable); + if (result != NULL) { + _PyFrozenSet_MaybeUntrack(result); + } + return result; } Py_ssize_t @@ -3010,6 +3038,11 @@ PySet_Add(PyObject *anyset, PyObject *key) // API limits the usage of `PySet_Add` to "fill in the values of brand // new frozensets before they are exposed to other code". In this case, // this can be done without a lock. + // Since another key is added to the set, we must track the frozenset + // if needed. + if (PyFrozenSet_CheckExact(anyset) && !PyObject_GC_IsTracked(anyset) && PyObject_GC_IsTracked(key)) { + _PyObject_GC_TRACK(anyset); + } return set_add_key((PySetObject *)anyset, key); } From 8fe8a94a7c050bc16cac9ec300f89c0f389f9a44 Mon Sep 17 00:00:00 2001 From: stratakis Date: Wed, 28 Jan 2026 14:30:17 +0100 Subject: [PATCH 097/133] gh-144194: Fix mmap failure check in perf_jit_trampoline.c (#143713) mmap() returns MAP_FAILED ((void*)-1) on error, not NULL. The current check never detects mmap failures, so jitdump initialization proceeds even when the memory mapping fails. --- .../2026-01-23-20-20-42.gh-issue-144194.IbXfxd.rst | 1 + Python/perf_jit_trampoline.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-23-20-20-42.gh-issue-144194.IbXfxd.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-23-20-20-42.gh-issue-144194.IbXfxd.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-23-20-20-42.gh-issue-144194.IbXfxd.rst new file mode 100644 index 00000000000..1f33284439c --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-23-20-20-42.gh-issue-144194.IbXfxd.rst @@ -0,0 +1 @@ +Fix error handling in perf jitdump initialization on memory allocation failure. diff --git a/Python/perf_jit_trampoline.c b/Python/perf_jit_trampoline.c index f51ab1b47a0..0ba856ea610 100644 --- a/Python/perf_jit_trampoline.c +++ b/Python/perf_jit_trampoline.c @@ -1083,7 +1083,8 @@ static void* perf_map_jit_init(void) { 0 // Offset 0 (first page) ); - if (perf_jit_map_state.mapped_buffer == NULL) { + if (perf_jit_map_state.mapped_buffer == MAP_FAILED) { + perf_jit_map_state.mapped_buffer = NULL; close(fd); return NULL; // Memory mapping failed } From 9b154aba7d08c0b5c72d1e415097852388e6d87b Mon Sep 17 00:00:00 2001 From: Giampaolo Rodola Date: Wed, 28 Jan 2026 15:04:40 +0100 Subject: [PATCH 098/133] gh-83069: Use efficient event-driven `subprocess.Popen.wait()` on Linux / macOS / BSD (#144047) --- Doc/library/subprocess.rst | 21 ++- Doc/whatsnew/3.15.rst | 14 ++ Lib/subprocess.py | 145 +++++++++++++++++- Lib/test/test_subprocess.py | 119 ++++++++++++++ ...6-01-19-16-45-16.gh-issue-83069.0TaeH9.rst | 7 + 5 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-19-16-45-16.gh-issue-83069.0TaeH9.rst diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index b8dfcc31077..cc4f032fb26 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -803,14 +803,29 @@ Instances of the :class:`Popen` class have the following methods: .. note:: - When the ``timeout`` parameter is not ``None``, then (on POSIX) the - function is implemented using a busy loop (non-blocking call and short - sleeps). Use the :mod:`asyncio` module for an asynchronous wait: see + When ``timeout`` is not ``None`` and the platform supports it, an + efficient event-driven mechanism is used to wait for process termination: + + - Linux >= 5.3 uses :func:`os.pidfd_open` + :func:`select.poll` + - macOS and other BSD variants use :func:`select.kqueue` + + ``KQ_FILTER_PROC`` + ``KQ_NOTE_EXIT`` + - Windows uses ``WaitForSingleObject`` + + If none of these mechanisms are available, the function falls back to a + busy loop (non-blocking call and short sleeps). + + .. note:: + + Use the :mod:`asyncio` module for an asynchronous wait: see :class:`asyncio.create_subprocess_exec`. .. versionchanged:: 3.3 *timeout* was added. + .. versionchanged:: 3.15 + if *timeout* is not ``None``, use efficient event-driven implementation + on Linux >= 5.3 and macOS / BSD. + .. method:: Popen.communicate(input=None, timeout=None) Interact with process: Send data to stdin. Read data from stdout and stderr, diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 19c01b71f02..22d8e249324 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -743,6 +743,20 @@ ssl (Contributed by Ron Frederick in :gh:`138252`.) +subprocess +---------- + +* :meth:`subprocess.Popen.wait`: when ``timeout`` is not ``None`` and the + platform supports it, an efficient event-driven mechanism is used to wait for + process termination: + + - Linux >= 5.3 uses :func:`os.pidfd_open` + :func:`select.poll`. + - macOS and other BSD variants use :func:`select.kqueue` + ``KQ_FILTER_PROC`` + ``KQ_NOTE_EXIT``. + - Windows keeps using ``WaitForSingleObject`` (unchanged). + + If none of these mechanisms are available, the function falls back to the + traditional busy loop (non-blocking call and short sleeps). + (Contributed by Giampaolo Rodola in :gh:`83069`). symtable -------- diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 3cebd7883fc..b943fba3d33 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -748,6 +748,60 @@ def _use_posix_spawn(): return False +def _can_use_pidfd_open(): + # Availability: Linux >= 5.3 + if not hasattr(os, "pidfd_open"): + return False + try: + pidfd = os.pidfd_open(os.getpid(), 0) + except OSError as err: + if err.errno in {errno.EMFILE, errno.ENFILE}: + # transitory 'too many open files' + return True + # likely blocked by security policy like SECCOMP (EPERM, + # EACCES, ENOSYS) + return False + else: + os.close(pidfd) + return True + + +def _can_use_kqueue(): + # Availability: macOS, BSD + names = ( + "kqueue", + "KQ_EV_ADD", + "KQ_EV_ONESHOT", + "KQ_FILTER_PROC", + "KQ_NOTE_EXIT", + ) + if not all(hasattr(select, x) for x in names): + return False + kq = None + try: + kq = select.kqueue() + kev = select.kevent( + os.getpid(), + filter=select.KQ_FILTER_PROC, + flags=select.KQ_EV_ADD | select.KQ_EV_ONESHOT, + fflags=select.KQ_NOTE_EXIT, + ) + kq.control([kev], 1, 0) + return True + except OSError as err: + if err.errno in {errno.EMFILE, errno.ENFILE}: + # transitory 'too many open files' + return True + return False + finally: + if kq is not None: + kq.close() + + +_CAN_USE_PIDFD_OPEN = not _mswindows and _can_use_pidfd_open() +_CAN_USE_KQUEUE = not _mswindows and _can_use_kqueue() + + # These are primarily fail-safe knobs for negatives. A True value does not # guarantee the given libc/syscall API will be used. _USE_POSIX_SPAWN = _use_posix_spawn() @@ -2046,14 +2100,100 @@ def _try_wait(self, wait_flags): sts = 0 return (pid, sts) + def _wait_pidfd(self, timeout): + """Wait for PID to terminate using pidfd_open() + poll(). + Linux >= 5.3 only. + """ + if not _CAN_USE_PIDFD_OPEN: + return False + try: + pidfd = os.pidfd_open(self.pid, 0) + except OSError: + # May be: + # - ESRCH: no such process + # - EMFILE, ENFILE: too many open files (usually 1024) + # - ENODEV: anonymous inode filesystem not supported + # - EPERM, EACCES, ENOSYS: undocumented; may happen if + # blocked by security policy like SECCOMP + return False + + try: + poller = select.poll() + poller.register(pidfd, select.POLLIN) + events = poller.poll(timeout * 1000) + if not events: + raise TimeoutExpired(self.args, timeout) + return True + finally: + os.close(pidfd) + + def _wait_kqueue(self, timeout): + """Wait for PID to terminate using kqueue(). macOS and BSD only.""" + if not _CAN_USE_KQUEUE: + return False + try: + kq = select.kqueue() + except OSError: + # likely EMFILE / ENFILE (too many open files) + return False + + try: + kev = select.kevent( + self.pid, + filter=select.KQ_FILTER_PROC, + flags=select.KQ_EV_ADD | select.KQ_EV_ONESHOT, + fflags=select.KQ_NOTE_EXIT, + ) + try: + events = kq.control([kev], 1, timeout) # wait + except OSError: + return False + else: + if not events: + raise TimeoutExpired(self.args, timeout) + return True + finally: + kq.close() def _wait(self, timeout): - """Internal implementation of wait() on POSIX.""" + """Internal implementation of wait() on POSIX. + + Uses efficient pidfd_open() + poll() on Linux or kqueue() + on macOS/BSD when available. Falls back to polling + waitpid(WNOHANG) otherwise. + """ if self.returncode is not None: return self.returncode if timeout is not None: - endtime = _time() + timeout + if timeout < 0: + raise TimeoutExpired(self.args, timeout) + started = _time() + endtime = started + timeout + + # Try efficient wait first. + if self._wait_pidfd(timeout) or self._wait_kqueue(timeout): + # Process is gone. At this point os.waitpid(pid, 0) + # will return immediately, but in very rare races + # the PID may have been reused. + # os.waitpid(pid, WNOHANG) ensures we attempt a + # non-blocking reap without blocking indefinitely. + with self._waitpid_lock: + if self.returncode is not None: + return self.returncode # Another thread waited. + (pid, sts) = self._try_wait(os.WNOHANG) + assert pid == self.pid or pid == 0 + if pid == self.pid: + self._handle_exitstatus(sts) + return self.returncode + # os.waitpid(pid, WNOHANG) returned 0 instead + # of our PID, meaning PID has not yet exited, + # even though poll() / kqueue() said so. Very + # rare and mostly theoretical. Fallback to busy + # polling. + elapsed = _time() - started + endtime -= elapsed + # Enter a busy loop if we have a timeout. This busy loop was # cribbed from Lib/threading.py in Thread.wait() at r71065. delay = 0.0005 # 500 us -> initial delay of 1 ms @@ -2085,6 +2225,7 @@ def _wait(self, timeout): # http://bugs.python.org/issue14396. if pid == self.pid: self._handle_exitstatus(sts) + return self.returncode diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 806a1e3fa30..0c567961184 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -1423,6 +1423,8 @@ def test_wait(self): def test_wait_timeout(self): p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(0.3)"]) + with self.assertRaises(subprocess.TimeoutExpired) as c: + p.wait(timeout=0) with self.assertRaises(subprocess.TimeoutExpired) as c: p.wait(timeout=0.0001) self.assertIn("0.0001", str(c.exception)) # For coverage of __str__. @@ -4094,5 +4096,122 @@ def test_broken_pipe_cleanup(self): self.assertTrue(proc.stdin.closed) + +class FastWaitTestCase(BaseTestCase): + """Tests for efficient (pidfd_open() + poll() / kqueue()) process + waiting in subprocess.Popen.wait(). + """ + CAN_USE_PIDFD_OPEN = subprocess._CAN_USE_PIDFD_OPEN + CAN_USE_KQUEUE = subprocess._CAN_USE_KQUEUE + COMMAND = [sys.executable, "-c", "import time; time.sleep(0.3)"] + WAIT_TIMEOUT = 0.0001 # 0.1 ms + + def assert_fast_waitpid_error(self, patch_point): + # Emulate a case where pidfd_open() or kqueue() fails. + # Busy-poll wait should be used as fallback. + exc = OSError(errno.EMFILE, os.strerror(errno.EMFILE)) + with mock.patch(patch_point, side_effect=exc) as m: + p = subprocess.Popen(self.COMMAND) + with self.assertRaises(subprocess.TimeoutExpired): + p.wait(self.WAIT_TIMEOUT) + self.assertEqual(p.wait(timeout=support.SHORT_TIMEOUT), 0) + self.assertTrue(m.called) + + @unittest.skipIf(not CAN_USE_PIDFD_OPEN, reason="needs pidfd_open()") + def test_wait_pidfd_open_error(self): + self.assert_fast_waitpid_error("os.pidfd_open") + + @unittest.skipIf(not CAN_USE_KQUEUE, reason="needs kqueue() for proc") + def test_wait_kqueue_error(self): + self.assert_fast_waitpid_error("select.kqueue") + + @unittest.skipIf(not CAN_USE_KQUEUE, reason="needs kqueue() for proc") + def test_kqueue_control_error(self): + # Emulate a case where kqueue.control() fails. Busy-poll wait + # should be used as fallback. + p = subprocess.Popen(self.COMMAND) + kq_mock = mock.Mock() + kq_mock.control.side_effect = OSError( + errno.EPERM, os.strerror(errno.EPERM) + ) + kq_mock.close = mock.Mock() + + with mock.patch("select.kqueue", return_value=kq_mock) as m: + with self.assertRaises(subprocess.TimeoutExpired): + p.wait(self.WAIT_TIMEOUT) + self.assertEqual(p.wait(timeout=support.SHORT_TIMEOUT), 0) + self.assertTrue(m.called) + + def assert_wait_race_condition(self, patch_target, real_func): + # Call pidfd_open() / kqueue(), then terminate the process. + # Make sure that the wait call (poll() / kqueue.control()) + # still works for a terminated PID. + p = subprocess.Popen(self.COMMAND) + + def wrapper(*args, **kwargs): + ret = real_func(*args, **kwargs) + try: + os.kill(p.pid, signal.SIGTERM) + os.waitpid(p.pid, 0) + except OSError: + pass + return ret + + with mock.patch(patch_target, side_effect=wrapper) as m: + status = p.wait(timeout=support.SHORT_TIMEOUT) + self.assertTrue(m.called) + self.assertEqual(status, 0) + + @unittest.skipIf(not CAN_USE_PIDFD_OPEN, reason="needs pidfd_open()") + def test_pidfd_open_race(self): + self.assert_wait_race_condition("os.pidfd_open", os.pidfd_open) + + @unittest.skipIf(not CAN_USE_KQUEUE, reason="needs kqueue() for proc") + def test_kqueue_race(self): + self.assert_wait_race_condition("select.kqueue", select.kqueue) + + def assert_notification_without_immediate_reap(self, patch_target): + # Verify fallback to busy polling when poll() / kqueue() + # succeeds, but waitpid(pid, WNOHANG) returns (0, 0). + def waitpid_wrapper(pid, flags): + nonlocal ncalls + ncalls += 1 + if ncalls == 1: + return (0, 0) + return real_waitpid(pid, flags) + + ncalls = 0 + real_waitpid = os.waitpid + with mock.patch.object(subprocess.Popen, patch_target, return_value=True) as m1: + with mock.patch("os.waitpid", side_effect=waitpid_wrapper) as m2: + p = subprocess.Popen(self.COMMAND) + with self.assertRaises(subprocess.TimeoutExpired): + p.wait(self.WAIT_TIMEOUT) + self.assertEqual(p.wait(timeout=support.SHORT_TIMEOUT), 0) + self.assertTrue(m1.called) + self.assertTrue(m2.called) + + @unittest.skipIf(not CAN_USE_PIDFD_OPEN, reason="needs pidfd_open()") + def test_pidfd_open_notification_without_immediate_reap(self): + self.assert_notification_without_immediate_reap("_wait_pidfd") + + @unittest.skipIf(not CAN_USE_KQUEUE, reason="needs kqueue() for proc") + def test_kqueue_notification_without_immediate_reap(self): + self.assert_notification_without_immediate_reap("_wait_kqueue") + + @unittest.skipUnless( + CAN_USE_PIDFD_OPEN or CAN_USE_KQUEUE, + "fast wait mechanism not available" + ) + def test_fast_path_avoid_busy_loop(self): + # assert that the busy loop is not called as long as the fast + # wait is available + with mock.patch('time.sleep') as m: + p = subprocess.Popen(self.COMMAND) + with self.assertRaises(subprocess.TimeoutExpired): + p.wait(self.WAIT_TIMEOUT) + self.assertEqual(p.wait(timeout=support.LONG_TIMEOUT), 0) + self.assertFalse(m.called) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2026-01-19-16-45-16.gh-issue-83069.0TaeH9.rst b/Misc/NEWS.d/next/Library/2026-01-19-16-45-16.gh-issue-83069.0TaeH9.rst new file mode 100644 index 00000000000..d0d4f2bd531 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-19-16-45-16.gh-issue-83069.0TaeH9.rst @@ -0,0 +1,7 @@ +:meth:`subprocess.Popen.wait`: when ``timeout`` is not ``None``, an efficient +event-driven mechanism now waits for process termination, if available. Linux +>= 5.3 uses :func:`os.pidfd_open` + :func:`select.poll`. macOS and other BSD +variants use :func:`select.kqueue` + ``KQ_FILTER_PROC`` + ``KQ_NOTE_EXIT``. +Windows keeps using ``WaitForSingleObject`` (unchanged). If none of these +mechanisms are available, the function falls back to the traditional busy loop +(non-blocking call and short sleeps). Patch by Giampaolo Rodola. From 6543720b63a62363de540deb5a6701f1ae431bce Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Wed, 28 Jan 2026 23:48:26 +0000 Subject: [PATCH 099/133] gh-142387: Reduce Android testbed API level to 33 (#144315) The emulator images for API level 34 and 35 have significant issues with image size and internet connectivity. Reverts the default API level used for testbed testing to 33. --- Android/testbed/app/build.gradle.kts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts index 14d43d8c4d5..4f184cf42d5 100644 --- a/Android/testbed/app/build.gradle.kts +++ b/Android/testbed/app/build.gradle.kts @@ -92,7 +92,12 @@ android { } throw GradleException("Failed to find API level in $androidEnvFile") } - targetSdk = 35 + + // This controls the API level of the maxVersion managed emulator, which is used + // by CI and cibuildwheel. 34 takes up too much disk space (#142289), 35 has + // issues connecting to the internet (#142387), and 36 and later are not + // available as aosp_atd images yet. + targetSdk = 33 versionCode = 1 versionName = "1.0" From b1bc868fba29846b0b27e4c78cb04eae423d9eb0 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Thu, 29 Jan 2026 12:26:11 +0000 Subject: [PATCH 100/133] gh-144319: Add huge pages support for pymalloc (#144320) --- Doc/c-api/memory.rst | 6 ++- Doc/using/configure.rst | 15 ++++++ Doc/whatsnew/3.15.rst | 6 +++ Include/internal/pycore_obmalloc.h | 22 +++++++-- ...-01-29-01-42-14.gh-issue-144319._7EtdB.rst | 1 + Objects/obmalloc.c | 20 ++++++++ PCbuild/build.bat | 3 ++ PCbuild/pyproject.props | 3 +- PCbuild/readme.txt | 5 ++ configure | 47 +++++++++++++++++++ configure.ac | 23 +++++++++ pyconfig.h.in | 3 ++ 12 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-01-42-14.gh-issue-144319._7EtdB.rst diff --git a/Doc/c-api/memory.rst b/Doc/c-api/memory.rst index a3be75a2a76..58f0de5d0fc 100644 --- a/Doc/c-api/memory.rst +++ b/Doc/c-api/memory.rst @@ -677,7 +677,11 @@ The pymalloc allocator Python has a *pymalloc* allocator optimized for small objects (smaller or equal to 512 bytes) with a short lifetime. It uses memory mappings called "arenas" with a fixed size of either 256 KiB on 32-bit platforms or 1 MiB on 64-bit -platforms. It falls back to :c:func:`PyMem_RawMalloc` and +platforms. When Python is configured with :option:`--with-pymalloc-hugepages`, +the arena size on 64-bit platforms is increased to 2 MiB to match the huge page +size, and arena allocation will attempt to use huge pages (``MAP_HUGETLB`` on +Linux, ``MEM_LARGE_PAGES`` on Windows) with automatic fallback to regular pages. +It falls back to :c:func:`PyMem_RawMalloc` and :c:func:`PyMem_RawRealloc` for allocations larger than 512 bytes. *pymalloc* is the :ref:`default allocator ` of the diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index af055d35290..c455272af72 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -783,6 +783,21 @@ also be used to improve performance. See also :envvar:`PYTHONMALLOC` environment variable. +.. option:: --with-pymalloc-hugepages + + Enable huge page support for :ref:`pymalloc ` arenas (disabled by + default). When enabled, the arena size on 64-bit platforms is increased to + 2 MiB and arena allocation uses ``MAP_HUGETLB`` (Linux) or + ``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages. + + The configure script checks that the platform supports ``MAP_HUGETLB`` + and emits a warning if it is not available. + + On Windows, use the ``--pymalloc-hugepages`` flag with ``build.bat`` or + set the ``UsePymallocHugepages`` MSBuild property. + + .. versionadded:: 3.15 + .. option:: --without-doc-strings Disable static documentation strings to reduce the memory footprint (enabled diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 22d8e249324..68c491f8a8c 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1477,6 +1477,12 @@ Build changes modules that are missing or packaged separately. (Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.) +* The new configure option :option:`--with-pymalloc-hugepages` enables huge + page support for :ref:`pymalloc ` arenas. When enabled, arena size + increases to 2 MiB and allocation uses ``MAP_HUGETLB`` (Linux) or + ``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages. + On Windows, use ``build.bat --pymalloc-hugepages``. + * Annotating anonymous mmap usage is now supported if Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME ` (Linux 5.17 or newer). Annotations are visible in ``/proc//maps`` if the kernel supports the feature diff --git a/Include/internal/pycore_obmalloc.h b/Include/internal/pycore_obmalloc.h index a7ba8f34073..0b23bb48dd5 100644 --- a/Include/internal/pycore_obmalloc.h +++ b/Include/internal/pycore_obmalloc.h @@ -208,7 +208,11 @@ typedef unsigned int pymem_uint; /* assuming >= 16 bits */ * mappings to reduce heap fragmentation. */ #ifdef USE_LARGE_ARENAS -#define ARENA_BITS 20 /* 1 MiB */ +# ifdef PYMALLOC_USE_HUGEPAGES +# define ARENA_BITS 21 /* 2 MiB */ +# else +# define ARENA_BITS 20 /* 1 MiB */ +# endif #else #define ARENA_BITS 18 /* 256 KiB */ #endif @@ -469,7 +473,7 @@ nfp free pools in usable_arenas. */ /* How many arena_objects do we initially allocate? - * 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the + * 16 = can allocate 16 arenas = 16 * ARENA_SIZE before growing the * `arenas` vector. */ #define INITIAL_ARENA_OBJECTS 16 @@ -512,7 +516,11 @@ struct _obmalloc_mgmt { memory address bit allocation for keys - 64-bit pointers, IGNORE_BITS=0 and 2^20 arena size: + ARENA_BITS is configurable: 20 (1 MiB) by default on 64-bit, or + 21 (2 MiB) when PYMALLOC_USE_HUGEPAGES is enabled. All bit widths + below are derived from ARENA_BITS automatically. + + 64-bit pointers, IGNORE_BITS=0 and 2^20 arena size (default): 15 -> MAP_TOP_BITS 15 -> MAP_MID_BITS 14 -> MAP_BOT_BITS @@ -520,6 +528,14 @@ struct _obmalloc_mgmt { ---- 64 + 64-bit pointers, IGNORE_BITS=0 and 2^21 arena size (hugepages): + 15 -> MAP_TOP_BITS + 15 -> MAP_MID_BITS + 13 -> MAP_BOT_BITS + 21 -> ideal aligned arena + ---- + 64 + 64-bit pointers, IGNORE_BITS=16, and 2^20 arena size: 16 -> IGNORE_BITS 10 -> MAP_TOP_BITS diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-01-42-14.gh-issue-144319._7EtdB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-01-42-14.gh-issue-144319._7EtdB.rst new file mode 100644 index 00000000000..805ba6067ed --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-01-42-14.gh-issue-144319._7EtdB.rst @@ -0,0 +1 @@ +Add huge pages support for the pymalloc allocator. Patch by Pablo Galindo diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index b24723f16cf..71dc4bf0d04 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -496,10 +496,30 @@ void * _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size) { #ifdef MS_WINDOWS +# ifdef PYMALLOC_USE_HUGEPAGES + void *ptr = VirtualAlloc(NULL, size, + MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, + PAGE_READWRITE); + if (ptr != NULL) + return ptr; + /* Fall back to regular pages */ +# endif return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #elif defined(ARENAS_USE_MMAP) void *ptr; +# ifdef PYMALLOC_USE_HUGEPAGES +# ifdef MAP_HUGETLB + ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); + if (ptr != MAP_FAILED) { + assert(ptr != NULL); + (void)_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc:hugepage"); + return ptr; + } + /* Fall back to regular pages */ +# endif +# endif ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (ptr == MAP_FAILED) diff --git a/PCbuild/build.bat b/PCbuild/build.bat index e4de9a80d76..8c24309be26 100644 --- a/PCbuild/build.bat +++ b/PCbuild/build.bat @@ -42,6 +42,7 @@ echo. --experimental-jit-interpreter Enable the experimental Tier 2 interprete echo. --pystats Enable PyStats collection. echo. --tail-call-interp Enable tail-calling interpreter (requires LLVM 19 or higher). echo. --enable-stackref-debug Enable stackref debugging mode. +echo. --pymalloc-hugepages Enable huge page support for pymalloc arenas. echo. echo.Available flags to avoid building certain modules. echo.These flags have no effect if '-e' is not given: @@ -100,6 +101,7 @@ if "%~1"=="--without-remote-debug" (set DisableRemoteDebug=true) & shift & goto if "%~1"=="--pystats" (set PyStats=1) & shift & goto CheckOpts if "%~1"=="--tail-call-interp" (set UseTailCallInterp=true) & shift & goto CheckOpts if "%~1"=="--enable-stackref-debug" (set StackRefDebug=true) & shift & goto CheckOpts +if "%~1"=="--pymalloc-hugepages" (set UsePymallocHugepages=true) & shift & goto CheckOpts rem These use the actual property names used by MSBuild. We could just let rem them in through the environment, but we specify them on the command line rem anyway for visibility so set defaults after this @@ -205,6 +207,7 @@ echo on /p:UseTailCallInterp=%UseTailCallInterp%^ /p:DisableRemoteDebug=%DisableRemoteDebug%^ /p:StackRefDebug=%StackRefDebug%^ + /p:UsePymallocHugepages=%UsePymallocHugepages%^ %1 %2 %3 %4 %5 %6 %7 %8 %9 @echo off diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index 53bfe5e3ea9..94ae718d58c 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -50,11 +50,12 @@ <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64' and $(PlatformToolset) != 'ClangCL'">_M_X64;$(_PlatformPreprocessorDefinition) <_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)$(PyDebugExt)"; <_FreeThreadedPreprocessorDefinition Condition="$(DisableGil) == 'true'">Py_GIL_DISABLED=1; + <_PymallocHugepagesPreprocessorDefinition Condition="$(UsePymallocHugepages) == 'true'">PYMALLOC_USE_HUGEPAGES=1; $(PySourcePath)Include;$(PySourcePath)Include\internal;$(PySourcePath)Include\internal\mimalloc;$(PySourcePath)PC;%(AdditionalIncludeDirectories) - WIN32;$(_Py3NamePreprocessorDefinition)$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PyStatsPreprocessorDefinition)$(_PydPreprocessorDefinition)$(_FreeThreadedPreprocessorDefinition)%(PreprocessorDefinitions) + WIN32;$(_Py3NamePreprocessorDefinition)$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PyStatsPreprocessorDefinition)$(_PydPreprocessorDefinition)$(_FreeThreadedPreprocessorDefinition)$(_PymallocHugepagesPreprocessorDefinition)%(PreprocessorDefinitions) _Py_USING_PGO=1;%(PreprocessorDefinitions) MaxSpeed diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 313982ed28a..c5d38296070 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -359,6 +359,11 @@ Supported flags are: * WITH_COMPUTED_GOTOS: build the interpreter using "computed gotos". Currently only supported by clang-cl. +* UsePymallocHugepages: enable huge page support for pymalloc arenas. + When enabled, the arena size on 64-bit platforms is increased to 2 MiB + and arena allocation uses MEM_LARGE_PAGES with automatic fallback to + regular pages. Can also be enabled via `--pymalloc-hugepages` flag. + Static library -------------- diff --git a/configure b/configure index c826a1bb856..30e35a0f552 100755 --- a/configure +++ b/configure @@ -1128,6 +1128,7 @@ enable_ipv6 with_doc_strings with_mimalloc with_pymalloc +with_pymalloc_hugepages with_c_locale_coercion with_valgrind with_dtrace @@ -1935,6 +1936,9 @@ Optional Packages: --with-mimalloc build with mimalloc memory allocator (default is yes if C11 stdatomic.h is available.) --with-pymalloc enable specialized mallocs (default is yes) + --with-pymalloc-hugepages + enable huge page support for pymalloc arenas + (default is no) --with-c-locale-coercion enable C locale coercion to a UTF-8 based locale (default is yes) @@ -18949,6 +18953,49 @@ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $with_pymalloc" >&5 printf "%s\n" "$with_pymalloc" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-pymalloc-hugepages" >&5 +printf %s "checking for --with-pymalloc-hugepages... " >&6; } + +# Check whether --with-pymalloc-hugepages was given. +if test ${with_pymalloc_hugepages+y} +then : + withval=$with_pymalloc_hugepages; +fi + +if test "$with_pymalloc_hugepages" = "yes" +then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main (void) +{ + +int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB; +(void)flags; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + +printf "%s\n" "#define PYMALLOC_USE_HUGEPAGES 1" >>confdefs.h + +else case e in #( + e) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: --with-pymalloc-hugepages requested but MAP_HUGETLB not found" >&5 +printf "%s\n" "$as_me: WARNING: --with-pymalloc-hugepages requested but MAP_HUGETLB not found" >&2;} + with_pymalloc_hugepages=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${with_pymalloc_hugepages:-no}" >&5 +printf "%s\n" "${with_pymalloc_hugepages:-no}" >&6; } + # Check for --with-c-locale-coercion { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-c-locale-coercion" >&5 printf %s "checking for --with-c-locale-coercion... " >&6; } diff --git a/configure.ac b/configure.ac index 322d33dd0e3..bc63d651f58 100644 --- a/configure.ac +++ b/configure.ac @@ -5061,6 +5061,29 @@ then fi AC_MSG_RESULT([$with_pymalloc]) +AC_MSG_CHECKING([for --with-pymalloc-hugepages]) +AC_ARG_WITH( + [pymalloc-hugepages], + [AS_HELP_STRING([--with-pymalloc-hugepages], + [enable huge page support for pymalloc arenas (default is no)])]) +if test "$with_pymalloc_hugepages" = "yes" +then + dnl configure only runs on Unix-like systems; Windows uses MEM_LARGE_PAGES + dnl via VirtualAlloc but does not use configure. Only check MAP_HUGETLB here. + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], [[ +int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB; +(void)flags; + ]])], + [AC_DEFINE([PYMALLOC_USE_HUGEPAGES], [1], + [Define to use huge pages for pymalloc arenas])], + [AC_MSG_WARN([--with-pymalloc-hugepages requested but MAP_HUGETLB not found]) + with_pymalloc_hugepages=no]) +fi +AC_MSG_RESULT([${with_pymalloc_hugepages:-no}]) + # Check for --with-c-locale-coercion AC_MSG_CHECKING([for --with-c-locale-coercion]) AC_ARG_WITH( diff --git a/pyconfig.h.in b/pyconfig.h.in index 4ae2abeabf1..3d901e01fe0 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1739,6 +1739,9 @@ /* Define as the preferred size in bits of long digits */ #undef PYLONG_BITS_IN_DIGIT +/* Define to use huge pages for pymalloc arenas */ +#undef PYMALLOC_USE_HUGEPAGES + /* enabled builtin hash modules */ #undef PY_BUILTIN_HASHLIB_HASHES From 927eb448aad6436d794ec9f55780013e25609600 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 29 Jan 2026 13:50:07 +0100 Subject: [PATCH 101/133] gh-144309: Build Python with POSIX 2024 (#144310) On FreeBSD, the ppoll() function is only visible if the POSIX version is 2024 or newer. --- .../Build/2026-01-28-19-04-12.gh-issue-144309.3sMFOh.rst | 1 + configure | 6 +++--- configure.ac | 8 ++++---- pyconfig.h.in | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-01-28-19-04-12.gh-issue-144309.3sMFOh.rst diff --git a/Misc/NEWS.d/next/Build/2026-01-28-19-04-12.gh-issue-144309.3sMFOh.rst b/Misc/NEWS.d/next/Build/2026-01-28-19-04-12.gh-issue-144309.3sMFOh.rst new file mode 100644 index 00000000000..c64ef494d27 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-01-28-19-04-12.gh-issue-144309.3sMFOh.rst @@ -0,0 +1 @@ +Build Python with POSIX 2024, instead of POSIX 2008. Patch by Victor Stinner. diff --git a/configure b/configure index 30e35a0f552..cd898368333 100755 --- a/configure +++ b/configure @@ -4757,9 +4757,9 @@ esac if test $define_xopen_source = yes then - # X/Open 7, incorporating POSIX.1-2008 + # X/Open 8, incorporating POSIX.1-2024 -printf "%s\n" "#define _XOPEN_SOURCE 700" >>confdefs.h +printf "%s\n" "#define _XOPEN_SOURCE 800" >>confdefs.h # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires @@ -4771,7 +4771,7 @@ printf "%s\n" "#define _XOPEN_SOURCE_EXTENDED 1" >>confdefs.h -printf "%s\n" "#define _POSIX_C_SOURCE 200809L" >>confdefs.h +printf "%s\n" "#define _POSIX_C_SOURCE 202405L" >>confdefs.h fi diff --git a/configure.ac b/configure.ac index bc63d651f58..e9b45d459fe 100644 --- a/configure.ac +++ b/configure.ac @@ -916,8 +916,8 @@ esac if test $define_xopen_source = yes then - # X/Open 7, incorporating POSIX.1-2008 - AC_DEFINE([_XOPEN_SOURCE], [700], + # X/Open 8, incorporating POSIX.1-2024 + AC_DEFINE([_XOPEN_SOURCE], [800], [Define to the level of X/Open that your system supports]) # On Tru64 Unix 4.0F, defining _XOPEN_SOURCE also requires @@ -927,8 +927,8 @@ then AC_DEFINE([_XOPEN_SOURCE_EXTENDED], [1], [Define to activate Unix95-and-earlier features]) - AC_DEFINE([_POSIX_C_SOURCE], [200809L], - [Define to activate features from IEEE Stds 1003.1-2008]) + AC_DEFINE([_POSIX_C_SOURCE], [202405L], + [Define to activate features from IEEE Std 1003.1-2024]) fi # On HP-UX mbstate_t requires _INCLUDE__STDC_A1_SOURCE diff --git a/pyconfig.h.in b/pyconfig.h.in index 3d901e01fe0..e2009b2d9ee 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -2042,7 +2042,7 @@ /* Define on NetBSD to activate all library features */ #undef _NETBSD_SOURCE -/* Define to activate features from IEEE Stds 1003.1-2008 */ +/* Define to activate features from IEEE Std 1003.1-2024 */ #undef _POSIX_C_SOURCE /* Define if you have POSIX threads, and your system does not define that. */ From a7cec565c17facf7fc2419f655fc43a621ae7dbc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jan 2026 15:04:37 +0200 Subject: [PATCH 102/133] gh-144206: Improve error messages for buffer overflow in fcntl.fcntl() and fcntl.ioctl() (GH-144273) --- ...-01-27-14-23-10.gh-issue-144206.l0un4U.rst | 2 ++ Modules/fcntlmodule.c | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-27-14-23-10.gh-issue-144206.l0un4U.rst diff --git a/Misc/NEWS.d/next/Library/2026-01-27-14-23-10.gh-issue-144206.l0un4U.rst b/Misc/NEWS.d/next/Library/2026-01-27-14-23-10.gh-issue-144206.l0un4U.rst new file mode 100644 index 00000000000..1e16d28a756 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-27-14-23-10.gh-issue-144206.l0un4U.rst @@ -0,0 +1,2 @@ +Improve error messages for buffer overflow in :func:`fcntl.fcntl` and +:func:`fcntl.ioctl`. diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c index e373bf36881..ce636c574ed 100644 --- a/Modules/fcntlmodule.c +++ b/Modules/fcntlmodule.c @@ -111,7 +111,11 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL; } if (memcmp(buf + len, guard, GUARDSZ) != 0) { - PyErr_SetString(PyExc_SystemError, "buffer overflow"); + PyErr_SetString(PyExc_SystemError, + "Possible stack corruption in fcntl() due to " + "buffer overflow. " + "Provide an argument of sufficient size as " + "determined by the operation."); return NULL; } return PyBytes_FromStringAndSize(buf, len); @@ -139,7 +143,11 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg) return NULL; } if (ptr[len] != '\0') { - PyErr_SetString(PyExc_SystemError, "buffer overflow"); + PyErr_SetString(PyExc_SystemError, + "Memory corruption in fcntl() due to " + "buffer overflow. " + "Provide an argument of sufficient size as " + "determined by the operation."); PyBytesWriter_Discard(writer); return NULL; } @@ -264,7 +272,12 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, } PyBuffer_Release(&view); if (ptr == buf && memcmp(buf + len, guard, GUARDSZ) != 0) { - PyErr_SetString(PyExc_SystemError, "buffer overflow"); + PyErr_SetString(PyExc_SystemError, + "Possible stack corruption in ioctl() due to " + "buffer overflow. " + "Provide a writable buffer argument of " + "sufficient size as determined by " + "the operation."); return NULL; } return PyLong_FromLong(ret); @@ -293,7 +306,11 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL; } if (memcmp(buf + len, guard, GUARDSZ) != 0) { - PyErr_SetString(PyExc_SystemError, "buffer overflow"); + PyErr_SetString(PyExc_SystemError, + "Possible stack corruption in ioctl() due to " + "buffer overflow. " + "Provide an argument of sufficient size as " + "determined by the operation."); return NULL; } return PyBytes_FromStringAndSize(buf, len); @@ -321,7 +338,11 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg, return NULL; } if (ptr[len] != '\0') { - PyErr_SetString(PyExc_SystemError, "buffer overflow"); + PyErr_SetString(PyExc_SystemError, + "Memory corruption in ioctl() due to " + "buffer overflow. " + "Provide an argument of sufficient size as " + "determined by the operation."); PyBytesWriter_Discard(writer); return NULL; } From 0fa1fc69f3ff0deb778e3c9f37cdc0c702bc8ad2 Mon Sep 17 00:00:00 2001 From: cui Date: Thu, 29 Jan 2026 21:26:38 +0800 Subject: [PATCH 103/133] gh-144322: typo This errors to These errors (#144323) --- Parser/tokenizer/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Parser/tokenizer/helpers.c b/Parser/tokenizer/helpers.c index a03531a7441..fda8216a300 100644 --- a/Parser/tokenizer/helpers.c +++ b/Parser/tokenizer/helpers.c @@ -65,7 +65,7 @@ _syntaxerror_range(struct tok_state *tok, const char *format, int _PyTokenizer_syntaxerror(struct tok_state *tok, const char *format, ...) { - // This errors are cleaned on startup. Todo: Fix it. + // These errors are cleaned on startup. Todo: Fix it. va_list vargs; va_start(vargs, format); int ret = _syntaxerror_range(tok, format, -1, -1, vargs); From 92c0ec2b007757287a5c4791437a8d5a6173ce58 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 29 Jan 2026 17:33:10 +0200 Subject: [PATCH 104/133] gh-144264: Speed up Base64 decoding of data containing ignored characters (GH-144265) Try the fast path again after decoding a quad the slow path. Use a bitmap cache for the ignorechars argument. --- Lib/test/test_binascii.py | 11 +++++ ...-01-27-10-02-04.gh-issue-144264.Wmzbol.rst | 3 ++ Modules/binascii.c | 42 ++++++++++++++----- 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-27-10-02-04.gh-issue-144264.Wmzbol.rst diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py index 4cfc332e89b..49accb08b62 100644 --- a/Lib/test/test_binascii.py +++ b/Lib/test/test_binascii.py @@ -202,6 +202,17 @@ def assertNonBase64Data(data, expected, ignorechars): assertNonBase64Data(b'a\nb==', b'i', ignorechars=bytearray(b'\n')) assertNonBase64Data(b'a\nb==', b'i', ignorechars=memoryview(b'\n')) + # Same cell in the cache: '\r' >> 3 == '\n' >> 3. + data = self.type2test(b'\r\n') + with self.assertRaises(binascii.Error): + binascii.a2b_base64(data, ignorechars=b'\r') + self.assertEqual(binascii.a2b_base64(data, ignorechars=b'\r\n'), b'') + # Same bit mask in the cache: '*' & 31 == '\n' & 31. + data = self.type2test(b'*\n') + with self.assertRaises(binascii.Error): + binascii.a2b_base64(data, ignorechars=b'*') + self.assertEqual(binascii.a2b_base64(data, ignorechars=b'*\n'), b'') + data = self.type2test(b'a\nb==') with self.assertRaises(TypeError): binascii.a2b_base64(data, ignorechars='') diff --git a/Misc/NEWS.d/next/Library/2026-01-27-10-02-04.gh-issue-144264.Wmzbol.rst b/Misc/NEWS.d/next/Library/2026-01-27-10-02-04.gh-issue-144264.Wmzbol.rst new file mode 100644 index 00000000000..11e3fdeb435 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-27-10-02-04.gh-issue-144264.Wmzbol.rst @@ -0,0 +1,3 @@ +Speed up Base64 decoding of data containing ignored characters (both in +non-strict mode and with an explicit *ignorechars* argument). +It is now up to 2 times faster for multiline Base64 data. diff --git a/Modules/binascii.c b/Modules/binascii.c index 593b27ac5ed..201e7798bb7 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -469,12 +469,23 @@ binascii_b2a_uu_impl(PyObject *module, Py_buffer *data, int backtick) return PyBytesWriter_FinishWithPointer(writer, ascii_data); } +typedef unsigned char ignorecache_t[32]; static int -ignorechar(unsigned char c, Py_buffer *ignorechars) +ignorechar(unsigned char c, const Py_buffer *ignorechars, + ignorecache_t ignorecache) { - return (ignorechars->buf != NULL && - memchr(ignorechars->buf, c, ignorechars->len)); + if (ignorechars == NULL) { + return 0; + } + if (ignorecache[c >> 3] & (1 << (c & 7))) { + return 1; + } + if (memchr(ignorechars->buf, c, ignorechars->len)) { + ignorecache[c >> 3] |= 1 << (c & 7); + return 1; + } + return 0; } /*[clinic input] @@ -508,6 +519,13 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, if (strict_mode == -1) { strict_mode = (ignorechars->buf != NULL); } + if (!strict_mode || ignorechars->buf == NULL || ignorechars->len == 0) { + ignorechars = NULL; + } + ignorecache_t ignorecache; + if (ignorechars != NULL) { + memset(ignorecache, 0, sizeof(ignorecache)); + } /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ @@ -517,8 +535,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, } unsigned char *bin_data = PyBytesWriter_GetData(writer); - size_t i = 0; /* Current position in input */ - +fastpath: /* Fast path: use optimized decoder for complete quads. * This works for both strict and non-strict mode for valid input. * The fast path stops at padding, invalid chars, or incomplete groups. @@ -527,7 +544,8 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, Py_ssize_t fast_chars = base64_decode_fast(ascii_data, (Py_ssize_t)ascii_len, bin_data, table_a2b_base64); if (fast_chars > 0) { - i = (size_t)fast_chars; + ascii_data += fast_chars; + ascii_len -= fast_chars; bin_data += (fast_chars / 4) * 3; } } @@ -536,8 +554,8 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, int quad_pos = 0; unsigned char leftchar = 0; int pads = 0; - for (; i < ascii_len; i++) { - unsigned char this_ch = ascii_data[i]; + for (; ascii_len; ascii_data++, ascii_len--) { + unsigned char this_ch = *ascii_data; /* Check for pad sequences and ignore ** the invalid ones. @@ -549,7 +567,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, if (quad_pos == 0) { state = get_binascii_state(module); if (state) { - PyErr_SetString(state->Error, (i == 0) + PyErr_SetString(state->Error, (ascii_data == data->buf) ? "Leading padding not allowed" : "Excess padding not allowed"); } @@ -580,7 +598,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, unsigned char v = table_a2b_base64[this_ch]; if (v >= 64) { - if (strict_mode && !ignorechar(this_ch, ignorechars)) { + if (strict_mode && !ignorechar(this_ch, ignorechars, ignorecache)) { state = get_binascii_state(module); if (state) { PyErr_SetString(state->Error, "Only base64 data is allowed"); @@ -621,7 +639,9 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode, quad_pos = 0; *bin_data++ = (leftchar << 6) | (v); leftchar = 0; - break; + ascii_data++; + ascii_len--; + goto fastpath; } } From 26996b59ab21fb0a5a4a585f386bbb05935c9bd9 Mon Sep 17 00:00:00 2001 From: Hai Zhu Date: Fri, 30 Jan 2026 00:58:01 +0800 Subject: [PATCH 105/133] gh-143946: Add more debug info in `optimize_uops` (GH-144262) --- Python/optimizer_analysis.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 35d72e851af..039aacf23ae 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -52,8 +52,6 @@ #define DPRINTF(level, ...) \ if (get_lltrace() >= (level)) { printf(__VA_ARGS__); } - - static void dump_abstract_stack(_Py_UOpsAbstractFrame *frame, JitOptRef *stack_pointer) { @@ -83,8 +81,25 @@ dump_abstract_stack(_Py_UOpsAbstractFrame *frame, JitOptRef *stack_pointer) fflush(stdout); } +static void +dump_uop(JitOptContext *ctx, const char *label, int index, + const _PyUOpInstruction *instr, JitOptRef *stack_pointer) +{ + if (get_lltrace() >= 3) { + printf("%4d %s: ", index, label); + _PyUOpPrint(instr); + printf("\n"); + if (get_lltrace() >= 5 && ctx->frame->code != ((PyCodeObject *)&_Py_InitCleanup)) { + dump_abstract_stack(ctx->frame, stack_pointer); + } + } +} + +#define DUMP_UOP dump_uop + #else #define DPRINTF(level, ...) + #define DUMP_UOP(ctx, label, index, instr, stack_pointer) #endif static int @@ -347,19 +362,19 @@ get_code_with_logging(_PyUOpInstruction *op) uint64_t push_operand = op->operand0; if (push_operand & 1) { co = (PyCodeObject *)(push_operand & ~1); - DPRINTF(3, "code=%p ", co); + DPRINTF(3, " code=%p\n", co); assert(PyCode_Check(co)); } else { PyFunctionObject *func = (PyFunctionObject *)push_operand; - DPRINTF(3, "func=%p ", func); + DPRINTF(3, " func=%p ", func); if (func == NULL) { DPRINTF(3, "\n"); DPRINTF(1, "Missing function\n"); return NULL; } co = (PyCodeObject *)func->func_code; - DPRINTF(3, "code=%p ", co); + DPRINTF(3, "code=%p\n", co); } return co; } @@ -493,16 +508,7 @@ optimize_uops( stack_pointer = ctx->frame->stack_pointer; } -#ifdef Py_DEBUG - if (get_lltrace() >= 3) { - printf("%4d abs: ", (int)(this_instr - trace)); - _PyUOpPrint(this_instr); - printf(" \n"); - if (get_lltrace() >= 5 && !CURRENT_FRAME_IS_INIT_SHIM()) { - dump_abstract_stack(ctx->frame, stack_pointer); - } - } -#endif + DUMP_UOP(ctx, "abs", this_instr - trace, this_instr, stack_pointer); _PyUOpInstruction *out_ptr = ctx->out_buffer.next; @@ -519,6 +525,7 @@ optimize_uops( *(ctx->out_buffer.next++) = *this_instr; } assert(ctx->frame != NULL); + DUMP_UOP(ctx, "out", uop_buffer_length(&ctx->out_buffer) - 1, out_ptr, stack_pointer); if (!CURRENT_FRAME_IS_INIT_SHIM() && !ctx->done) { DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); ctx->frame->stack_pointer = stack_pointer; From 14c5339a389a1161da4521d4c41236acb448baad Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Fri, 30 Jan 2026 01:08:14 +0800 Subject: [PATCH 106/133] Test: fix stale uops usage in `test_capi/test_opt.py` (GH-144239) Signed-off-by: Yongtao Huang --- Lib/test/test_capi/test_opt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 7808700f6a2..a379d1be2f9 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3750,6 +3750,7 @@ def test_is_none(n): res, ex = self._run_with_optimizer(test_is_none, TIER2_THRESHOLD) self.assertEqual(res, True) self.assertIsNotNone(ex) + uops = get_opnames(ex) self.assertIn("_IS_OP", uops) self.assertIn("_POP_TOP_NOP", uops) From 219b7ac9d562701bbde21d7e17845c4942b83338 Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Fri, 30 Jan 2026 02:50:54 +0800 Subject: [PATCH 107/133] gh-144307: Fix a reference leak during module teardown (GH-144308) Signed-off-by: Yongtao Huang Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> --- .../2026-01-29-02-18-08.gh-issue-144307.CLbm_o.rst | 1 + Python/pylifecycle.c | 1 + 2 files changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-02-18-08.gh-issue-144307.CLbm_o.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-02-18-08.gh-issue-144307.CLbm_o.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-02-18-08.gh-issue-144307.CLbm_o.rst new file mode 100644 index 00000000000..d6928e643dc --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-29-02-18-08.gh-issue-144307.CLbm_o.rst @@ -0,0 +1 @@ +Prevent a reference leak in module teardown at interpreter finalization. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 88dbdb6d139..d3ed08de1d1 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1622,6 +1622,7 @@ finalize_remove_modules(PyObject *modules, int verbose) PyObject *value = PyObject_GetItem(modules, key); if (value == NULL) { PyErr_FormatUnraisable("Exception ignored while removing modules"); + Py_DECREF(key); continue; } CLEAR_MODULE(key, value); From 1b081434666d244d2fa083d47251d90175ac69da Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 29 Jan 2026 22:32:09 +0100 Subject: [PATCH 108/133] gh-143192 Avoid incref/decref pair in long_bitwise (gh-143194) Remove unnecessary reference count operations in long_bitwise in order to avoid reference count contention in the free-threading build. --- ...-12-29-19-31-46.gh-issue-143192.JxGAyl.rst | 1 + Objects/longobject.c | 37 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst new file mode 100644 index 00000000000..3a99b3d9e6a --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-29-19-31-46.gh-issue-143192.JxGAyl.rst @@ -0,0 +1 @@ +Improve performance of bitwise operations on multi-digit ints. diff --git a/Objects/longobject.c b/Objects/longobject.c index 74958cb8b9b..7ce5d0535b8 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5589,46 +5589,45 @@ long_bitwise(PyLongObject *a, Py_ssize_t size_a, size_b, size_z, i; PyLongObject *z; + PyLongObject *new_a = NULL; + PyLongObject *new_b = NULL; + /* Bitwise operations for negative numbers operate as though on a two's complement representation. So convert arguments from sign-magnitude to two's complement, and convert the result back to sign-magnitude at the end. */ - /* If a is negative, replace it by its two's complement. */ size_a = _PyLong_DigitCount(a); + size_b = _PyLong_DigitCount(b); + /* Swap a and b if necessary to ensure size_a >= size_b. */ + if (size_a < size_b) { + z = a; a = b; b = z; + size_z = size_a; size_a = size_b; size_b = size_z; + } + + /* If a is negative, replace it by its two's complement. */ nega = _PyLong_IsNegative(a); if (nega) { z = long_alloc(size_a); if (z == NULL) return NULL; v_complement(z->long_value.ob_digit, a->long_value.ob_digit, size_a); + new_a = z; // reference to decrement instead of a itself a = z; } - else - /* Keep reference count consistent. */ - Py_INCREF(a); /* Same for b. */ - size_b = _PyLong_DigitCount(b); negb = _PyLong_IsNegative(b); if (negb) { z = long_alloc(size_b); if (z == NULL) { - Py_DECREF(a); + Py_XDECREF(new_a); return NULL; } v_complement(z->long_value.ob_digit, b->long_value.ob_digit, size_b); + new_b = z; // reference to decrement instead of b itself b = z; } - else - Py_INCREF(b); - - /* Swap a and b if necessary to ensure size_a >= size_b. */ - if (size_a < size_b) { - z = a; a = b; b = z; - size_z = size_a; size_a = size_b; size_b = size_z; - negz = nega; nega = negb; negb = negz; - } /* JRH: The original logic here was to allocate the result value (z) as the longer of the two operands. However, there are some cases @@ -5658,8 +5657,8 @@ long_bitwise(PyLongObject *a, the final two's complement of z doesn't overflow. */ z = long_alloc(size_z + negz); if (z == NULL) { - Py_DECREF(a); - Py_DECREF(b); + Py_XDECREF(new_a); + Py_XDECREF(new_b); return NULL; } @@ -5696,8 +5695,8 @@ long_bitwise(PyLongObject *a, v_complement(z->long_value.ob_digit, z->long_value.ob_digit, size_z+1); } - Py_DECREF(a); - Py_DECREF(b); + Py_XDECREF(new_a); + Py_XDECREF(new_b); return (PyObject *)maybe_small_long(long_normalize(z)); } From 5f57f6970bdea45cc2b192d612bfd8199f51491e Mon Sep 17 00:00:00 2001 From: Divyanshu Choudhury Date: Fri, 30 Jan 2026 06:05:30 +0530 Subject: [PATCH 109/133] gh-143423: Fix free-threaded build detection in sampling profiler (#143426) --- Lib/profiling/sampling/sample.py | 29 +++++++++++-------- ...-01-05-05-31-05.gh-issue-143423.X7YdnR.rst | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-05-05-31-05.gh-issue-143423.X7YdnR.rst diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index e73306ebf29..f657849e72b 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -42,6 +42,7 @@ def _pause_threads(unwinder, blocking): LiveStatsCollector = None _FREE_THREADED_BUILD = sysconfig.get_config_var("Py_GIL_DISABLED") is not None + # Minimum number of samples required before showing the TUI # If fewer samples are collected, we skip the TUI and just print a message MIN_SAMPLES_FOR_TUI = 200 @@ -64,19 +65,23 @@ def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MOD self.realtime_stats = False def _new_unwinder(self, native, gc, opcodes, skip_non_matching_threads): - if _FREE_THREADED_BUILD: - unwinder = _remote_debugging.RemoteUnwinder( - self.pid, all_threads=self.all_threads, mode=self.mode, native=native, gc=gc, - opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads, - cache_frames=True, stats=self.collect_stats - ) + kwargs = {} + if _FREE_THREADED_BUILD or self.all_threads: + kwargs['all_threads'] = self.all_threads else: - unwinder = _remote_debugging.RemoteUnwinder( - self.pid, only_active_thread=bool(self.all_threads), mode=self.mode, native=native, gc=gc, - opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads, - cache_frames=True, stats=self.collect_stats - ) - return unwinder + kwargs['only_active_thread'] = bool(self.all_threads) + + return _remote_debugging.RemoteUnwinder( + self.pid, + mode=self.mode, + native=native, + gc=gc, + opcodes=opcodes, + skip_non_matching_threads=skip_non_matching_threads, + cache_frames=True, + stats=self.collect_stats, + **kwargs + ) def sample(self, collector, duration_sec=None, *, async_aware=False): sample_interval_sec = self.sample_interval_usec / 1_000_000 diff --git a/Misc/NEWS.d/next/Library/2026-01-05-05-31-05.gh-issue-143423.X7YdnR.rst b/Misc/NEWS.d/next/Library/2026-01-05-05-31-05.gh-issue-143423.X7YdnR.rst new file mode 100644 index 00000000000..d9276dfd400 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-05-05-31-05.gh-issue-143423.X7YdnR.rst @@ -0,0 +1 @@ +Fix free-threaded build detection in the sampling profiler when Py_GIL_DISABLED is set to 0. From be4ee8ee420adb211b77645f30ca1eb9356ed1c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maurycy=20Paw=C5=82owski-Wiero=C5=84ski?= Date: Fri, 30 Jan 2026 16:13:21 +0100 Subject: [PATCH 110/133] gh-144342: Use `time.sleep` in `profiling.sampling` (#144343) --- Lib/profiling/sampling/sample.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py index f657849e72b..c6abfb1c8ee 100644 --- a/Lib/profiling/sampling/sample.py +++ b/Lib/profiling/sampling/sample.py @@ -100,7 +100,11 @@ def sample(self, collector, duration_sec=None, *, async_aware=False): break current_time = time.perf_counter() - if next_time < current_time: + if next_time > current_time: + sleep_time = (next_time - current_time) * 0.9 + if sleep_time > 0.0001: + time.sleep(sleep_time) + elif next_time < current_time: try: with _pause_threads(self.unwinder, self.blocking): if async_aware == "all": From 1dc12b2883c89045469f3c401157d4df13f535f0 Mon Sep 17 00:00:00 2001 From: Hai Zhu Date: Fri, 30 Jan 2026 23:25:19 +0800 Subject: [PATCH 111/133] gh-144145: Track nullness of properties in the Tier 2 JIT optimizer (GH-144122) --- Include/internal/pycore_optimizer.h | 8 + Include/internal/pycore_optimizer_types.h | 36 + Include/internal/pycore_uop_ids.h | 1788 +++++++++-------- Include/internal/pycore_uop_metadata.h | 42 + ...-01-30-09-47-29.gh-issue-144145.mxJyUj.rst | 1 + Python/bytecodes.c | 31 + Python/executor_cases.c.h | 292 +++ Python/optimizer_analysis.c | 12 +- Python/optimizer_bytecodes.c | 31 +- Python/optimizer_cases.c.h | 50 +- Python/optimizer_symbols.c | 200 +- 11 files changed, 1589 insertions(+), 902 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 2ee518fb82f..89e08e86ed6 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -37,10 +37,15 @@ typedef struct _JitOptContext { // Arena for the symbolic types. ty_arena t_arena; + // Arena for the descriptor mappings. + descr_arena d_arena; + JitOptRef *n_consumed; JitOptRef *limit; JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; _PyJitUopBuffer out_buffer; + // Index of the last escaped uop in out_buffer. + int last_escape_index; } JitOptContext; @@ -295,6 +300,9 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value, extern bool _Py_uop_sym_is_compact_int(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx); extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym); +extern JitOptRef _Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version); +extern JitOptRef _Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index); +extern JitOptRef _Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value); extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind); extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true); diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index b4b93e83538..1996ce10735 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -16,6 +16,10 @@ extern "C" { #define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5) +// Maximum descriptor mappings per object tracked symbolically +#define MAX_SYMBOLIC_DESCR_SIZE 16 +#define DESCR_ARENA_SIZE (MAX_SYMBOLIC_DESCR_SIZE * 100) + // Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) #define MAX_ABSTRACT_FRAME_DEPTH (16) @@ -41,6 +45,7 @@ typedef enum _JitSymType { JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, JIT_SYM_PREDICATE_TAG = 11, + JIT_SYM_DESCR_TAG = 12, } JitSymType; typedef struct _jit_opt_known_class { @@ -91,6 +96,31 @@ typedef struct { uint8_t tag; } JitOptCompactInt; +/* +Mapping from slot index or attribute offset to its symbolic value. +SAFETY: +This structure is used for both STORE_ATTR_SLOT and STORE_ATTR_INSTANCE_VALUE. +These two never appear on the same object type because: +__slots__ classes don't have Py_TPFLAGS_INLINE_VALUES +Therefore, there is no index collision between slot offsets and inline value offsets. +Note: +STORE_ATTR_WITH_HINT is NOT currently tracked. +If we want to track it in the future, we need to be careful about +potential index collisions with STORE_ATTR_INSTANCE_VALUE. +*/ +typedef struct { + uint16_t slot_index; + uint16_t symbol; +} JitOptDescrMapping; + +typedef struct _jit_opt_descr { + uint8_t tag; + uint8_t num_descrs; + uint16_t last_modified_index; // Index in out_buffer when this object was last modified + uint32_t type_version; + JitOptDescrMapping *descrs; +} JitOptDescrObject; + typedef union _jit_opt_symbol { uint8_t tag; JitOptKnownClass cls; @@ -99,6 +129,7 @@ typedef union _jit_opt_symbol { JitOptTuple tuple; JitOptTruthiness truthiness; JitOptCompactInt compact; + JitOptDescrObject descr; JitOptPredicate predicate; } JitOptSymbol; @@ -128,6 +159,11 @@ typedef struct ty_arena { JitOptSymbol arena[TY_ARENA_SIZE]; } ty_arena; +typedef struct descr_arena { + int descr_curr_number; + int descr_max_number; + JitOptDescrMapping arena[DESCR_ARENA_SIZE]; +} descr_arena; #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 8712d1afc75..a1abe168605 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -340,905 +340,915 @@ extern "C" { #define _START_EXECUTOR 548 #define _STORE_ATTR 549 #define _STORE_ATTR_INSTANCE_VALUE 550 -#define _STORE_ATTR_SLOT 551 -#define _STORE_ATTR_WITH_HINT 552 +#define _STORE_ATTR_INSTANCE_VALUE_NULL 551 +#define _STORE_ATTR_SLOT 552 +#define _STORE_ATTR_SLOT_NULL 553 +#define _STORE_ATTR_WITH_HINT 554 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 553 -#define _STORE_SUBSCR 554 -#define _STORE_SUBSCR_DICT 555 -#define _STORE_SUBSCR_LIST_INT 556 -#define _SWAP 557 -#define _SWAP_2 558 -#define _SWAP_3 559 -#define _SWAP_FAST 560 -#define _SWAP_FAST_0 561 -#define _SWAP_FAST_1 562 -#define _SWAP_FAST_2 563 -#define _SWAP_FAST_3 564 -#define _SWAP_FAST_4 565 -#define _SWAP_FAST_5 566 -#define _SWAP_FAST_6 567 -#define _SWAP_FAST_7 568 -#define _TIER2_RESUME_CHECK 569 -#define _TO_BOOL 570 +#define _STORE_SLICE 555 +#define _STORE_SUBSCR 556 +#define _STORE_SUBSCR_DICT 557 +#define _STORE_SUBSCR_LIST_INT 558 +#define _SWAP 559 +#define _SWAP_2 560 +#define _SWAP_3 561 +#define _SWAP_FAST 562 +#define _SWAP_FAST_0 563 +#define _SWAP_FAST_1 564 +#define _SWAP_FAST_2 565 +#define _SWAP_FAST_3 566 +#define _SWAP_FAST_4 567 +#define _SWAP_FAST_5 568 +#define _SWAP_FAST_6 569 +#define _SWAP_FAST_7 570 +#define _TIER2_RESUME_CHECK 571 +#define _TO_BOOL 572 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 571 -#define _TO_BOOL_LIST 572 +#define _TO_BOOL_INT 573 +#define _TO_BOOL_LIST 574 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 573 +#define _TO_BOOL_STR 575 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 574 -#define _UNARY_NEGATIVE 575 +#define _UNARY_INVERT 576 +#define _UNARY_NEGATIVE 577 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 576 -#define _UNPACK_SEQUENCE_LIST 577 -#define _UNPACK_SEQUENCE_TUPLE 578 -#define _UNPACK_SEQUENCE_TWO_TUPLE 579 +#define _UNPACK_SEQUENCE 578 +#define _UNPACK_SEQUENCE_LIST 579 +#define _UNPACK_SEQUENCE_TUPLE 580 +#define _UNPACK_SEQUENCE_TWO_TUPLE 581 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 579 -#define _BINARY_OP_r23 580 -#define _BINARY_OP_ADD_FLOAT_r03 581 -#define _BINARY_OP_ADD_FLOAT_r13 582 -#define _BINARY_OP_ADD_FLOAT_r23 583 -#define _BINARY_OP_ADD_INT_r03 584 -#define _BINARY_OP_ADD_INT_r13 585 -#define _BINARY_OP_ADD_INT_r23 586 -#define _BINARY_OP_ADD_UNICODE_r03 587 -#define _BINARY_OP_ADD_UNICODE_r13 588 -#define _BINARY_OP_ADD_UNICODE_r23 589 -#define _BINARY_OP_EXTEND_r23 590 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 591 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 592 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 593 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 594 -#define _BINARY_OP_MULTIPLY_INT_r03 595 -#define _BINARY_OP_MULTIPLY_INT_r13 596 -#define _BINARY_OP_MULTIPLY_INT_r23 597 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 598 -#define _BINARY_OP_SUBSCR_DICT_r23 599 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 600 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 601 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 602 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 603 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 604 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 605 -#define _BINARY_OP_SUBSCR_STR_INT_r23 606 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 607 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 608 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 609 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 610 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 611 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 612 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 613 -#define _BINARY_OP_SUBTRACT_INT_r03 614 -#define _BINARY_OP_SUBTRACT_INT_r13 615 -#define _BINARY_OP_SUBTRACT_INT_r23 616 -#define _BINARY_SLICE_r31 617 -#define _BUILD_INTERPOLATION_r01 618 -#define _BUILD_LIST_r01 619 -#define _BUILD_MAP_r01 620 -#define _BUILD_SET_r01 621 -#define _BUILD_SLICE_r01 622 -#define _BUILD_STRING_r01 623 -#define _BUILD_TEMPLATE_r21 624 -#define _BUILD_TUPLE_r01 625 -#define _CALL_BUILTIN_CLASS_r01 626 -#define _CALL_BUILTIN_FAST_r01 627 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 628 -#define _CALL_BUILTIN_O_r03 629 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 630 -#define _CALL_INTRINSIC_1_r11 631 -#define _CALL_INTRINSIC_2_r21 632 -#define _CALL_ISINSTANCE_r31 633 -#define _CALL_KW_NON_PY_r11 634 -#define _CALL_LEN_r33 635 -#define _CALL_LIST_APPEND_r03 636 -#define _CALL_LIST_APPEND_r13 637 -#define _CALL_LIST_APPEND_r23 638 -#define _CALL_LIST_APPEND_r33 639 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 640 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 641 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 642 -#define _CALL_METHOD_DESCRIPTOR_O_r03 643 -#define _CALL_NON_PY_GENERAL_r01 644 -#define _CALL_STR_1_r32 645 -#define _CALL_TUPLE_1_r32 646 -#define _CALL_TYPE_1_r02 647 -#define _CALL_TYPE_1_r12 648 -#define _CALL_TYPE_1_r22 649 -#define _CALL_TYPE_1_r32 650 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 651 -#define _CHECK_ATTR_CLASS_r01 652 -#define _CHECK_ATTR_CLASS_r11 653 -#define _CHECK_ATTR_CLASS_r22 654 -#define _CHECK_ATTR_CLASS_r33 655 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 656 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 657 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 658 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 659 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 660 -#define _CHECK_EG_MATCH_r22 661 -#define _CHECK_EXC_MATCH_r22 662 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 663 -#define _CHECK_FUNCTION_VERSION_r00 664 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 665 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 666 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 667 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 668 -#define _CHECK_FUNCTION_VERSION_KW_r11 669 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 670 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 671 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 672 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 673 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 674 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 675 -#define _CHECK_IS_PY_CALLABLE_EX_r03 676 -#define _CHECK_IS_PY_CALLABLE_EX_r13 677 -#define _CHECK_IS_PY_CALLABLE_EX_r23 678 -#define _CHECK_IS_PY_CALLABLE_EX_r33 679 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 680 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 681 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 682 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 683 -#define _CHECK_METHOD_VERSION_r00 684 -#define _CHECK_METHOD_VERSION_KW_r11 685 -#define _CHECK_PEP_523_r00 686 -#define _CHECK_PEP_523_r11 687 -#define _CHECK_PEP_523_r22 688 -#define _CHECK_PEP_523_r33 689 -#define _CHECK_PERIODIC_r00 690 -#define _CHECK_PERIODIC_AT_END_r00 691 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 692 -#define _CHECK_RECURSION_REMAINING_r00 693 -#define _CHECK_RECURSION_REMAINING_r11 694 -#define _CHECK_RECURSION_REMAINING_r22 695 -#define _CHECK_RECURSION_REMAINING_r33 696 -#define _CHECK_STACK_SPACE_r00 697 -#define _CHECK_STACK_SPACE_OPERAND_r00 698 -#define _CHECK_STACK_SPACE_OPERAND_r11 699 -#define _CHECK_STACK_SPACE_OPERAND_r22 700 -#define _CHECK_STACK_SPACE_OPERAND_r33 701 -#define _CHECK_VALIDITY_r00 702 -#define _CHECK_VALIDITY_r11 703 -#define _CHECK_VALIDITY_r22 704 -#define _CHECK_VALIDITY_r33 705 -#define _COLD_DYNAMIC_EXIT_r00 706 -#define _COLD_EXIT_r00 707 -#define _COMPARE_OP_r21 708 -#define _COMPARE_OP_FLOAT_r03 709 -#define _COMPARE_OP_FLOAT_r13 710 -#define _COMPARE_OP_FLOAT_r23 711 -#define _COMPARE_OP_INT_r23 712 -#define _COMPARE_OP_STR_r23 713 -#define _CONTAINS_OP_r23 714 -#define _CONTAINS_OP_DICT_r23 715 -#define _CONTAINS_OP_SET_r23 716 -#define _CONVERT_VALUE_r11 717 -#define _COPY_r01 718 -#define _COPY_1_r02 719 -#define _COPY_1_r12 720 -#define _COPY_1_r23 721 -#define _COPY_2_r03 722 -#define _COPY_2_r13 723 -#define _COPY_2_r23 724 -#define _COPY_3_r03 725 -#define _COPY_3_r13 726 -#define _COPY_3_r23 727 -#define _COPY_3_r33 728 -#define _COPY_FREE_VARS_r00 729 -#define _COPY_FREE_VARS_r11 730 -#define _COPY_FREE_VARS_r22 731 -#define _COPY_FREE_VARS_r33 732 -#define _CREATE_INIT_FRAME_r01 733 -#define _DELETE_ATTR_r10 734 -#define _DELETE_DEREF_r00 735 -#define _DELETE_FAST_r00 736 -#define _DELETE_GLOBAL_r00 737 -#define _DELETE_NAME_r00 738 -#define _DELETE_SUBSCR_r20 739 -#define _DEOPT_r00 740 -#define _DEOPT_r10 741 -#define _DEOPT_r20 742 -#define _DEOPT_r30 743 -#define _DICT_MERGE_r10 744 -#define _DICT_UPDATE_r10 745 -#define _DO_CALL_r01 746 -#define _DO_CALL_FUNCTION_EX_r31 747 -#define _DO_CALL_KW_r11 748 -#define _DYNAMIC_EXIT_r00 749 -#define _DYNAMIC_EXIT_r10 750 -#define _DYNAMIC_EXIT_r20 751 -#define _DYNAMIC_EXIT_r30 752 -#define _END_FOR_r10 753 -#define _END_SEND_r21 754 -#define _ERROR_POP_N_r00 755 -#define _EXIT_INIT_CHECK_r10 756 -#define _EXIT_TRACE_r00 757 -#define _EXIT_TRACE_r10 758 -#define _EXIT_TRACE_r20 759 -#define _EXIT_TRACE_r30 760 -#define _EXPAND_METHOD_r00 761 -#define _EXPAND_METHOD_KW_r11 762 -#define _FATAL_ERROR_r00 763 -#define _FATAL_ERROR_r11 764 -#define _FATAL_ERROR_r22 765 -#define _FATAL_ERROR_r33 766 -#define _FORMAT_SIMPLE_r11 767 -#define _FORMAT_WITH_SPEC_r21 768 -#define _FOR_ITER_r23 769 -#define _FOR_ITER_GEN_FRAME_r03 770 -#define _FOR_ITER_GEN_FRAME_r13 771 -#define _FOR_ITER_GEN_FRAME_r23 772 -#define _FOR_ITER_TIER_TWO_r23 773 -#define _GET_AITER_r11 774 -#define _GET_ANEXT_r12 775 -#define _GET_AWAITABLE_r11 776 -#define _GET_ITER_r12 777 -#define _GET_LEN_r12 778 -#define _GET_YIELD_FROM_ITER_r11 779 -#define _GUARD_BINARY_OP_EXTEND_r22 780 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 781 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 782 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 783 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 784 -#define _GUARD_BIT_IS_SET_POP_r00 785 -#define _GUARD_BIT_IS_SET_POP_r10 786 -#define _GUARD_BIT_IS_SET_POP_r21 787 -#define _GUARD_BIT_IS_SET_POP_r32 788 -#define _GUARD_BIT_IS_SET_POP_4_r00 789 -#define _GUARD_BIT_IS_SET_POP_4_r10 790 -#define _GUARD_BIT_IS_SET_POP_4_r21 791 -#define _GUARD_BIT_IS_SET_POP_4_r32 792 -#define _GUARD_BIT_IS_SET_POP_5_r00 793 -#define _GUARD_BIT_IS_SET_POP_5_r10 794 -#define _GUARD_BIT_IS_SET_POP_5_r21 795 -#define _GUARD_BIT_IS_SET_POP_5_r32 796 -#define _GUARD_BIT_IS_SET_POP_6_r00 797 -#define _GUARD_BIT_IS_SET_POP_6_r10 798 -#define _GUARD_BIT_IS_SET_POP_6_r21 799 -#define _GUARD_BIT_IS_SET_POP_6_r32 800 -#define _GUARD_BIT_IS_SET_POP_7_r00 801 -#define _GUARD_BIT_IS_SET_POP_7_r10 802 -#define _GUARD_BIT_IS_SET_POP_7_r21 803 -#define _GUARD_BIT_IS_SET_POP_7_r32 804 -#define _GUARD_BIT_IS_UNSET_POP_r00 805 -#define _GUARD_BIT_IS_UNSET_POP_r10 806 -#define _GUARD_BIT_IS_UNSET_POP_r21 807 -#define _GUARD_BIT_IS_UNSET_POP_r32 808 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 809 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 810 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 811 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 812 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 813 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 814 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 815 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 816 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 817 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 818 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 819 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 820 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 821 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 822 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 823 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 824 -#define _GUARD_CALLABLE_ISINSTANCE_r03 825 -#define _GUARD_CALLABLE_ISINSTANCE_r13 826 -#define _GUARD_CALLABLE_ISINSTANCE_r23 827 -#define _GUARD_CALLABLE_ISINSTANCE_r33 828 -#define _GUARD_CALLABLE_LEN_r03 829 -#define _GUARD_CALLABLE_LEN_r13 830 -#define _GUARD_CALLABLE_LEN_r23 831 -#define _GUARD_CALLABLE_LEN_r33 832 -#define _GUARD_CALLABLE_LIST_APPEND_r03 833 -#define _GUARD_CALLABLE_LIST_APPEND_r13 834 -#define _GUARD_CALLABLE_LIST_APPEND_r23 835 -#define _GUARD_CALLABLE_LIST_APPEND_r33 836 -#define _GUARD_CALLABLE_STR_1_r03 837 -#define _GUARD_CALLABLE_STR_1_r13 838 -#define _GUARD_CALLABLE_STR_1_r23 839 -#define _GUARD_CALLABLE_STR_1_r33 840 -#define _GUARD_CALLABLE_TUPLE_1_r03 841 -#define _GUARD_CALLABLE_TUPLE_1_r13 842 -#define _GUARD_CALLABLE_TUPLE_1_r23 843 -#define _GUARD_CALLABLE_TUPLE_1_r33 844 -#define _GUARD_CALLABLE_TYPE_1_r03 845 -#define _GUARD_CALLABLE_TYPE_1_r13 846 -#define _GUARD_CALLABLE_TYPE_1_r23 847 -#define _GUARD_CALLABLE_TYPE_1_r33 848 -#define _GUARD_DORV_NO_DICT_r01 849 -#define _GUARD_DORV_NO_DICT_r11 850 -#define _GUARD_DORV_NO_DICT_r22 851 -#define _GUARD_DORV_NO_DICT_r33 852 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 853 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 854 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 855 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 856 -#define _GUARD_GLOBALS_VERSION_r00 857 -#define _GUARD_GLOBALS_VERSION_r11 858 -#define _GUARD_GLOBALS_VERSION_r22 859 -#define _GUARD_GLOBALS_VERSION_r33 860 -#define _GUARD_IP_RETURN_GENERATOR_r00 861 -#define _GUARD_IP_RETURN_GENERATOR_r11 862 -#define _GUARD_IP_RETURN_GENERATOR_r22 863 -#define _GUARD_IP_RETURN_GENERATOR_r33 864 -#define _GUARD_IP_RETURN_VALUE_r00 865 -#define _GUARD_IP_RETURN_VALUE_r11 866 -#define _GUARD_IP_RETURN_VALUE_r22 867 -#define _GUARD_IP_RETURN_VALUE_r33 868 -#define _GUARD_IP_YIELD_VALUE_r00 869 -#define _GUARD_IP_YIELD_VALUE_r11 870 -#define _GUARD_IP_YIELD_VALUE_r22 871 -#define _GUARD_IP_YIELD_VALUE_r33 872 -#define _GUARD_IP__PUSH_FRAME_r00 873 -#define _GUARD_IP__PUSH_FRAME_r11 874 -#define _GUARD_IP__PUSH_FRAME_r22 875 -#define _GUARD_IP__PUSH_FRAME_r33 876 -#define _GUARD_IS_FALSE_POP_r00 877 -#define _GUARD_IS_FALSE_POP_r10 878 -#define _GUARD_IS_FALSE_POP_r21 879 -#define _GUARD_IS_FALSE_POP_r32 880 -#define _GUARD_IS_NONE_POP_r00 881 -#define _GUARD_IS_NONE_POP_r10 882 -#define _GUARD_IS_NONE_POP_r21 883 -#define _GUARD_IS_NONE_POP_r32 884 -#define _GUARD_IS_NOT_NONE_POP_r10 885 -#define _GUARD_IS_TRUE_POP_r00 886 -#define _GUARD_IS_TRUE_POP_r10 887 -#define _GUARD_IS_TRUE_POP_r21 888 -#define _GUARD_IS_TRUE_POP_r32 889 -#define _GUARD_KEYS_VERSION_r01 890 -#define _GUARD_KEYS_VERSION_r11 891 -#define _GUARD_KEYS_VERSION_r22 892 -#define _GUARD_KEYS_VERSION_r33 893 -#define _GUARD_NOS_COMPACT_ASCII_r02 894 -#define _GUARD_NOS_COMPACT_ASCII_r12 895 -#define _GUARD_NOS_COMPACT_ASCII_r22 896 -#define _GUARD_NOS_COMPACT_ASCII_r33 897 -#define _GUARD_NOS_DICT_r02 898 -#define _GUARD_NOS_DICT_r12 899 -#define _GUARD_NOS_DICT_r22 900 -#define _GUARD_NOS_DICT_r33 901 -#define _GUARD_NOS_FLOAT_r02 902 -#define _GUARD_NOS_FLOAT_r12 903 -#define _GUARD_NOS_FLOAT_r22 904 -#define _GUARD_NOS_FLOAT_r33 905 -#define _GUARD_NOS_INT_r02 906 -#define _GUARD_NOS_INT_r12 907 -#define _GUARD_NOS_INT_r22 908 -#define _GUARD_NOS_INT_r33 909 -#define _GUARD_NOS_LIST_r02 910 -#define _GUARD_NOS_LIST_r12 911 -#define _GUARD_NOS_LIST_r22 912 -#define _GUARD_NOS_LIST_r33 913 -#define _GUARD_NOS_NOT_NULL_r02 914 -#define _GUARD_NOS_NOT_NULL_r12 915 -#define _GUARD_NOS_NOT_NULL_r22 916 -#define _GUARD_NOS_NOT_NULL_r33 917 -#define _GUARD_NOS_NULL_r02 918 -#define _GUARD_NOS_NULL_r12 919 -#define _GUARD_NOS_NULL_r22 920 -#define _GUARD_NOS_NULL_r33 921 -#define _GUARD_NOS_OVERFLOWED_r02 922 -#define _GUARD_NOS_OVERFLOWED_r12 923 -#define _GUARD_NOS_OVERFLOWED_r22 924 -#define _GUARD_NOS_OVERFLOWED_r33 925 -#define _GUARD_NOS_TUPLE_r02 926 -#define _GUARD_NOS_TUPLE_r12 927 -#define _GUARD_NOS_TUPLE_r22 928 -#define _GUARD_NOS_TUPLE_r33 929 -#define _GUARD_NOS_UNICODE_r02 930 -#define _GUARD_NOS_UNICODE_r12 931 -#define _GUARD_NOS_UNICODE_r22 932 -#define _GUARD_NOS_UNICODE_r33 933 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 934 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 935 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 936 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 937 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 938 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 939 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 940 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 941 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 942 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 943 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 944 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 945 -#define _GUARD_THIRD_NULL_r03 946 -#define _GUARD_THIRD_NULL_r13 947 -#define _GUARD_THIRD_NULL_r23 948 -#define _GUARD_THIRD_NULL_r33 949 -#define _GUARD_TOS_ANY_SET_r01 950 -#define _GUARD_TOS_ANY_SET_r11 951 -#define _GUARD_TOS_ANY_SET_r22 952 -#define _GUARD_TOS_ANY_SET_r33 953 -#define _GUARD_TOS_DICT_r01 954 -#define _GUARD_TOS_DICT_r11 955 -#define _GUARD_TOS_DICT_r22 956 -#define _GUARD_TOS_DICT_r33 957 -#define _GUARD_TOS_FLOAT_r01 958 -#define _GUARD_TOS_FLOAT_r11 959 -#define _GUARD_TOS_FLOAT_r22 960 -#define _GUARD_TOS_FLOAT_r33 961 -#define _GUARD_TOS_INT_r01 962 -#define _GUARD_TOS_INT_r11 963 -#define _GUARD_TOS_INT_r22 964 -#define _GUARD_TOS_INT_r33 965 -#define _GUARD_TOS_LIST_r01 966 -#define _GUARD_TOS_LIST_r11 967 -#define _GUARD_TOS_LIST_r22 968 -#define _GUARD_TOS_LIST_r33 969 -#define _GUARD_TOS_OVERFLOWED_r01 970 -#define _GUARD_TOS_OVERFLOWED_r11 971 -#define _GUARD_TOS_OVERFLOWED_r22 972 -#define _GUARD_TOS_OVERFLOWED_r33 973 -#define _GUARD_TOS_SLICE_r01 974 -#define _GUARD_TOS_SLICE_r11 975 -#define _GUARD_TOS_SLICE_r22 976 -#define _GUARD_TOS_SLICE_r33 977 -#define _GUARD_TOS_TUPLE_r01 978 -#define _GUARD_TOS_TUPLE_r11 979 -#define _GUARD_TOS_TUPLE_r22 980 -#define _GUARD_TOS_TUPLE_r33 981 -#define _GUARD_TOS_UNICODE_r01 982 -#define _GUARD_TOS_UNICODE_r11 983 -#define _GUARD_TOS_UNICODE_r22 984 -#define _GUARD_TOS_UNICODE_r33 985 -#define _GUARD_TYPE_VERSION_r01 986 -#define _GUARD_TYPE_VERSION_r11 987 -#define _GUARD_TYPE_VERSION_r22 988 -#define _GUARD_TYPE_VERSION_r33 989 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 990 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 991 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 992 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 993 -#define _HANDLE_PENDING_AND_DEOPT_r00 994 -#define _HANDLE_PENDING_AND_DEOPT_r10 995 -#define _HANDLE_PENDING_AND_DEOPT_r20 996 -#define _HANDLE_PENDING_AND_DEOPT_r30 997 -#define _IMPORT_FROM_r12 998 -#define _IMPORT_NAME_r21 999 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1000 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1001 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1002 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1003 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1004 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1005 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1006 -#define _INSERT_1_LOAD_CONST_INLINE_r02 1007 -#define _INSERT_1_LOAD_CONST_INLINE_r12 1008 -#define _INSERT_1_LOAD_CONST_INLINE_r23 1009 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1010 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1011 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1012 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1013 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1014 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1015 -#define _INSERT_NULL_r10 1016 -#define _INSTRUMENTED_FOR_ITER_r23 1017 -#define _INSTRUMENTED_INSTRUCTION_r00 1018 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1019 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1020 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1021 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1022 -#define _INSTRUMENTED_LINE_r00 1023 -#define _INSTRUMENTED_NOT_TAKEN_r00 1024 -#define _INSTRUMENTED_NOT_TAKEN_r11 1025 -#define _INSTRUMENTED_NOT_TAKEN_r22 1026 -#define _INSTRUMENTED_NOT_TAKEN_r33 1027 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1028 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1029 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1030 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1031 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1032 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1033 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1034 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1035 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1036 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1037 -#define _IS_NONE_r11 1038 -#define _IS_OP_r03 1039 -#define _IS_OP_r13 1040 -#define _IS_OP_r23 1041 -#define _ITER_CHECK_LIST_r02 1042 -#define _ITER_CHECK_LIST_r12 1043 -#define _ITER_CHECK_LIST_r22 1044 -#define _ITER_CHECK_LIST_r33 1045 -#define _ITER_CHECK_RANGE_r02 1046 -#define _ITER_CHECK_RANGE_r12 1047 -#define _ITER_CHECK_RANGE_r22 1048 -#define _ITER_CHECK_RANGE_r33 1049 -#define _ITER_CHECK_TUPLE_r02 1050 -#define _ITER_CHECK_TUPLE_r12 1051 -#define _ITER_CHECK_TUPLE_r22 1052 -#define _ITER_CHECK_TUPLE_r33 1053 -#define _ITER_JUMP_LIST_r02 1054 -#define _ITER_JUMP_LIST_r12 1055 -#define _ITER_JUMP_LIST_r22 1056 -#define _ITER_JUMP_LIST_r33 1057 -#define _ITER_JUMP_RANGE_r02 1058 -#define _ITER_JUMP_RANGE_r12 1059 -#define _ITER_JUMP_RANGE_r22 1060 -#define _ITER_JUMP_RANGE_r33 1061 -#define _ITER_JUMP_TUPLE_r02 1062 -#define _ITER_JUMP_TUPLE_r12 1063 -#define _ITER_JUMP_TUPLE_r22 1064 -#define _ITER_JUMP_TUPLE_r33 1065 -#define _ITER_NEXT_LIST_r23 1066 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1067 -#define _ITER_NEXT_RANGE_r03 1068 -#define _ITER_NEXT_RANGE_r13 1069 -#define _ITER_NEXT_RANGE_r23 1070 -#define _ITER_NEXT_TUPLE_r03 1071 -#define _ITER_NEXT_TUPLE_r13 1072 -#define _ITER_NEXT_TUPLE_r23 1073 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1074 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1075 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1076 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1077 -#define _JUMP_TO_TOP_r00 1078 -#define _LIST_APPEND_r10 1079 -#define _LIST_EXTEND_r10 1080 -#define _LOAD_ATTR_r10 1081 -#define _LOAD_ATTR_CLASS_r11 1082 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1083 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1084 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1085 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1086 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1087 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1088 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1089 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1090 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1091 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1092 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1093 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1094 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1095 -#define _LOAD_ATTR_MODULE_r12 1096 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1097 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1098 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1099 -#define _LOAD_ATTR_SLOT_r02 1100 -#define _LOAD_ATTR_SLOT_r12 1101 -#define _LOAD_ATTR_SLOT_r23 1102 -#define _LOAD_ATTR_WITH_HINT_r12 1103 -#define _LOAD_BUILD_CLASS_r01 1104 -#define _LOAD_BYTECODE_r00 1105 -#define _LOAD_COMMON_CONSTANT_r01 1106 -#define _LOAD_COMMON_CONSTANT_r12 1107 -#define _LOAD_COMMON_CONSTANT_r23 1108 -#define _LOAD_CONST_r01 1109 -#define _LOAD_CONST_r12 1110 -#define _LOAD_CONST_r23 1111 -#define _LOAD_CONST_INLINE_r01 1112 -#define _LOAD_CONST_INLINE_r12 1113 -#define _LOAD_CONST_INLINE_r23 1114 -#define _LOAD_CONST_INLINE_BORROW_r01 1115 -#define _LOAD_CONST_INLINE_BORROW_r12 1116 -#define _LOAD_CONST_INLINE_BORROW_r23 1117 -#define _LOAD_CONST_UNDER_INLINE_r02 1118 -#define _LOAD_CONST_UNDER_INLINE_r12 1119 -#define _LOAD_CONST_UNDER_INLINE_r23 1120 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1121 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1122 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1123 -#define _LOAD_DEREF_r01 1124 -#define _LOAD_FAST_r01 1125 -#define _LOAD_FAST_r12 1126 -#define _LOAD_FAST_r23 1127 -#define _LOAD_FAST_0_r01 1128 -#define _LOAD_FAST_0_r12 1129 -#define _LOAD_FAST_0_r23 1130 -#define _LOAD_FAST_1_r01 1131 -#define _LOAD_FAST_1_r12 1132 -#define _LOAD_FAST_1_r23 1133 -#define _LOAD_FAST_2_r01 1134 -#define _LOAD_FAST_2_r12 1135 -#define _LOAD_FAST_2_r23 1136 -#define _LOAD_FAST_3_r01 1137 -#define _LOAD_FAST_3_r12 1138 -#define _LOAD_FAST_3_r23 1139 -#define _LOAD_FAST_4_r01 1140 -#define _LOAD_FAST_4_r12 1141 -#define _LOAD_FAST_4_r23 1142 -#define _LOAD_FAST_5_r01 1143 -#define _LOAD_FAST_5_r12 1144 -#define _LOAD_FAST_5_r23 1145 -#define _LOAD_FAST_6_r01 1146 -#define _LOAD_FAST_6_r12 1147 -#define _LOAD_FAST_6_r23 1148 -#define _LOAD_FAST_7_r01 1149 -#define _LOAD_FAST_7_r12 1150 -#define _LOAD_FAST_7_r23 1151 -#define _LOAD_FAST_AND_CLEAR_r01 1152 -#define _LOAD_FAST_AND_CLEAR_r12 1153 -#define _LOAD_FAST_AND_CLEAR_r23 1154 -#define _LOAD_FAST_BORROW_r01 1155 -#define _LOAD_FAST_BORROW_r12 1156 -#define _LOAD_FAST_BORROW_r23 1157 -#define _LOAD_FAST_BORROW_0_r01 1158 -#define _LOAD_FAST_BORROW_0_r12 1159 -#define _LOAD_FAST_BORROW_0_r23 1160 -#define _LOAD_FAST_BORROW_1_r01 1161 -#define _LOAD_FAST_BORROW_1_r12 1162 -#define _LOAD_FAST_BORROW_1_r23 1163 -#define _LOAD_FAST_BORROW_2_r01 1164 -#define _LOAD_FAST_BORROW_2_r12 1165 -#define _LOAD_FAST_BORROW_2_r23 1166 -#define _LOAD_FAST_BORROW_3_r01 1167 -#define _LOAD_FAST_BORROW_3_r12 1168 -#define _LOAD_FAST_BORROW_3_r23 1169 -#define _LOAD_FAST_BORROW_4_r01 1170 -#define _LOAD_FAST_BORROW_4_r12 1171 -#define _LOAD_FAST_BORROW_4_r23 1172 -#define _LOAD_FAST_BORROW_5_r01 1173 -#define _LOAD_FAST_BORROW_5_r12 1174 -#define _LOAD_FAST_BORROW_5_r23 1175 -#define _LOAD_FAST_BORROW_6_r01 1176 -#define _LOAD_FAST_BORROW_6_r12 1177 -#define _LOAD_FAST_BORROW_6_r23 1178 -#define _LOAD_FAST_BORROW_7_r01 1179 -#define _LOAD_FAST_BORROW_7_r12 1180 -#define _LOAD_FAST_BORROW_7_r23 1181 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1182 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1183 -#define _LOAD_FAST_CHECK_r01 1184 -#define _LOAD_FAST_CHECK_r12 1185 -#define _LOAD_FAST_CHECK_r23 1186 -#define _LOAD_FAST_LOAD_FAST_r02 1187 -#define _LOAD_FAST_LOAD_FAST_r13 1188 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1189 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1190 -#define _LOAD_GLOBAL_r00 1191 -#define _LOAD_GLOBAL_BUILTINS_r01 1192 -#define _LOAD_GLOBAL_MODULE_r01 1193 -#define _LOAD_LOCALS_r01 1194 -#define _LOAD_LOCALS_r12 1195 -#define _LOAD_LOCALS_r23 1196 -#define _LOAD_NAME_r01 1197 -#define _LOAD_SMALL_INT_r01 1198 -#define _LOAD_SMALL_INT_r12 1199 -#define _LOAD_SMALL_INT_r23 1200 -#define _LOAD_SMALL_INT_0_r01 1201 -#define _LOAD_SMALL_INT_0_r12 1202 -#define _LOAD_SMALL_INT_0_r23 1203 -#define _LOAD_SMALL_INT_1_r01 1204 -#define _LOAD_SMALL_INT_1_r12 1205 -#define _LOAD_SMALL_INT_1_r23 1206 -#define _LOAD_SMALL_INT_2_r01 1207 -#define _LOAD_SMALL_INT_2_r12 1208 -#define _LOAD_SMALL_INT_2_r23 1209 -#define _LOAD_SMALL_INT_3_r01 1210 -#define _LOAD_SMALL_INT_3_r12 1211 -#define _LOAD_SMALL_INT_3_r23 1212 -#define _LOAD_SPECIAL_r00 1213 -#define _LOAD_SUPER_ATTR_ATTR_r31 1214 -#define _LOAD_SUPER_ATTR_METHOD_r32 1215 -#define _MAKE_CALLARGS_A_TUPLE_r33 1216 -#define _MAKE_CELL_r00 1217 -#define _MAKE_FUNCTION_r11 1218 -#define _MAKE_WARM_r00 1219 -#define _MAKE_WARM_r11 1220 -#define _MAKE_WARM_r22 1221 -#define _MAKE_WARM_r33 1222 -#define _MAP_ADD_r20 1223 -#define _MATCH_CLASS_r31 1224 -#define _MATCH_KEYS_r23 1225 -#define _MATCH_MAPPING_r02 1226 -#define _MATCH_MAPPING_r12 1227 -#define _MATCH_MAPPING_r23 1228 -#define _MATCH_SEQUENCE_r02 1229 -#define _MATCH_SEQUENCE_r12 1230 -#define _MATCH_SEQUENCE_r23 1231 -#define _MAYBE_EXPAND_METHOD_r00 1232 -#define _MAYBE_EXPAND_METHOD_KW_r11 1233 -#define _MONITOR_CALL_r00 1234 -#define _MONITOR_CALL_KW_r11 1235 -#define _MONITOR_JUMP_BACKWARD_r00 1236 -#define _MONITOR_JUMP_BACKWARD_r11 1237 -#define _MONITOR_JUMP_BACKWARD_r22 1238 -#define _MONITOR_JUMP_BACKWARD_r33 1239 -#define _MONITOR_RESUME_r00 1240 -#define _NOP_r00 1241 -#define _NOP_r11 1242 -#define _NOP_r22 1243 -#define _NOP_r33 1244 -#define _POP_CALL_r20 1245 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1246 -#define _POP_CALL_ONE_r30 1247 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1248 -#define _POP_CALL_TWO_r30 1249 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1250 -#define _POP_EXCEPT_r10 1251 -#define _POP_ITER_r20 1252 -#define _POP_JUMP_IF_FALSE_r00 1253 -#define _POP_JUMP_IF_FALSE_r10 1254 -#define _POP_JUMP_IF_FALSE_r21 1255 -#define _POP_JUMP_IF_FALSE_r32 1256 -#define _POP_JUMP_IF_TRUE_r00 1257 -#define _POP_JUMP_IF_TRUE_r10 1258 -#define _POP_JUMP_IF_TRUE_r21 1259 -#define _POP_JUMP_IF_TRUE_r32 1260 -#define _POP_TOP_r10 1261 -#define _POP_TOP_FLOAT_r00 1262 -#define _POP_TOP_FLOAT_r10 1263 -#define _POP_TOP_FLOAT_r21 1264 -#define _POP_TOP_FLOAT_r32 1265 -#define _POP_TOP_INT_r00 1266 -#define _POP_TOP_INT_r10 1267 -#define _POP_TOP_INT_r21 1268 -#define _POP_TOP_INT_r32 1269 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1270 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1271 -#define _POP_TOP_NOP_r00 1272 -#define _POP_TOP_NOP_r10 1273 -#define _POP_TOP_NOP_r21 1274 -#define _POP_TOP_NOP_r32 1275 -#define _POP_TOP_UNICODE_r00 1276 -#define _POP_TOP_UNICODE_r10 1277 -#define _POP_TOP_UNICODE_r21 1278 -#define _POP_TOP_UNICODE_r32 1279 -#define _POP_TWO_r20 1280 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1281 -#define _PUSH_EXC_INFO_r02 1282 -#define _PUSH_EXC_INFO_r12 1283 -#define _PUSH_EXC_INFO_r23 1284 -#define _PUSH_FRAME_r10 1285 -#define _PUSH_NULL_r01 1286 -#define _PUSH_NULL_r12 1287 -#define _PUSH_NULL_r23 1288 -#define _PUSH_NULL_CONDITIONAL_r00 1289 -#define _PY_FRAME_EX_r31 1290 -#define _PY_FRAME_GENERAL_r01 1291 -#define _PY_FRAME_KW_r11 1292 -#define _QUICKEN_RESUME_r00 1293 -#define _QUICKEN_RESUME_r11 1294 -#define _QUICKEN_RESUME_r22 1295 -#define _QUICKEN_RESUME_r33 1296 -#define _REPLACE_WITH_TRUE_r02 1297 -#define _REPLACE_WITH_TRUE_r12 1298 -#define _REPLACE_WITH_TRUE_r23 1299 -#define _RESUME_CHECK_r00 1300 -#define _RESUME_CHECK_r11 1301 -#define _RESUME_CHECK_r22 1302 -#define _RESUME_CHECK_r33 1303 -#define _RETURN_GENERATOR_r01 1304 -#define _RETURN_VALUE_r11 1305 -#define _SAVE_RETURN_OFFSET_r00 1306 -#define _SAVE_RETURN_OFFSET_r11 1307 -#define _SAVE_RETURN_OFFSET_r22 1308 -#define _SAVE_RETURN_OFFSET_r33 1309 -#define _SEND_r22 1310 -#define _SEND_GEN_FRAME_r22 1311 -#define _SETUP_ANNOTATIONS_r00 1312 -#define _SET_ADD_r10 1313 -#define _SET_FUNCTION_ATTRIBUTE_r01 1314 -#define _SET_FUNCTION_ATTRIBUTE_r11 1315 -#define _SET_FUNCTION_ATTRIBUTE_r21 1316 -#define _SET_FUNCTION_ATTRIBUTE_r32 1317 -#define _SET_IP_r00 1318 -#define _SET_IP_r11 1319 -#define _SET_IP_r22 1320 -#define _SET_IP_r33 1321 -#define _SET_UPDATE_r10 1322 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1323 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1324 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1325 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1326 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1327 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1328 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1329 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1330 -#define _SPILL_OR_RELOAD_r01 1331 -#define _SPILL_OR_RELOAD_r02 1332 -#define _SPILL_OR_RELOAD_r03 1333 -#define _SPILL_OR_RELOAD_r10 1334 -#define _SPILL_OR_RELOAD_r12 1335 -#define _SPILL_OR_RELOAD_r13 1336 -#define _SPILL_OR_RELOAD_r20 1337 -#define _SPILL_OR_RELOAD_r21 1338 -#define _SPILL_OR_RELOAD_r23 1339 -#define _SPILL_OR_RELOAD_r30 1340 -#define _SPILL_OR_RELOAD_r31 1341 -#define _SPILL_OR_RELOAD_r32 1342 -#define _START_EXECUTOR_r00 1343 -#define _STORE_ATTR_r20 1344 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1345 -#define _STORE_ATTR_SLOT_r21 1346 -#define _STORE_ATTR_WITH_HINT_r21 1347 -#define _STORE_DEREF_r10 1348 -#define _STORE_FAST_LOAD_FAST_r11 1349 -#define _STORE_FAST_STORE_FAST_r20 1350 -#define _STORE_GLOBAL_r10 1351 -#define _STORE_NAME_r10 1352 -#define _STORE_SLICE_r30 1353 -#define _STORE_SUBSCR_r30 1354 -#define _STORE_SUBSCR_DICT_r31 1355 -#define _STORE_SUBSCR_LIST_INT_r32 1356 -#define _SWAP_r11 1357 -#define _SWAP_2_r02 1358 -#define _SWAP_2_r12 1359 -#define _SWAP_2_r22 1360 -#define _SWAP_2_r33 1361 -#define _SWAP_3_r03 1362 -#define _SWAP_3_r13 1363 -#define _SWAP_3_r23 1364 -#define _SWAP_3_r33 1365 -#define _SWAP_FAST_r01 1366 -#define _SWAP_FAST_r11 1367 -#define _SWAP_FAST_r22 1368 -#define _SWAP_FAST_r33 1369 -#define _SWAP_FAST_0_r01 1370 -#define _SWAP_FAST_0_r11 1371 -#define _SWAP_FAST_0_r22 1372 -#define _SWAP_FAST_0_r33 1373 -#define _SWAP_FAST_1_r01 1374 -#define _SWAP_FAST_1_r11 1375 -#define _SWAP_FAST_1_r22 1376 -#define _SWAP_FAST_1_r33 1377 -#define _SWAP_FAST_2_r01 1378 -#define _SWAP_FAST_2_r11 1379 -#define _SWAP_FAST_2_r22 1380 -#define _SWAP_FAST_2_r33 1381 -#define _SWAP_FAST_3_r01 1382 -#define _SWAP_FAST_3_r11 1383 -#define _SWAP_FAST_3_r22 1384 -#define _SWAP_FAST_3_r33 1385 -#define _SWAP_FAST_4_r01 1386 -#define _SWAP_FAST_4_r11 1387 -#define _SWAP_FAST_4_r22 1388 -#define _SWAP_FAST_4_r33 1389 -#define _SWAP_FAST_5_r01 1390 -#define _SWAP_FAST_5_r11 1391 -#define _SWAP_FAST_5_r22 1392 -#define _SWAP_FAST_5_r33 1393 -#define _SWAP_FAST_6_r01 1394 -#define _SWAP_FAST_6_r11 1395 -#define _SWAP_FAST_6_r22 1396 -#define _SWAP_FAST_6_r33 1397 -#define _SWAP_FAST_7_r01 1398 -#define _SWAP_FAST_7_r11 1399 -#define _SWAP_FAST_7_r22 1400 -#define _SWAP_FAST_7_r33 1401 -#define _TIER2_RESUME_CHECK_r00 1402 -#define _TIER2_RESUME_CHECK_r11 1403 -#define _TIER2_RESUME_CHECK_r22 1404 -#define _TIER2_RESUME_CHECK_r33 1405 -#define _TO_BOOL_r11 1406 -#define _TO_BOOL_BOOL_r01 1407 -#define _TO_BOOL_BOOL_r11 1408 -#define _TO_BOOL_BOOL_r22 1409 -#define _TO_BOOL_BOOL_r33 1410 -#define _TO_BOOL_INT_r02 1411 -#define _TO_BOOL_INT_r12 1412 -#define _TO_BOOL_INT_r23 1413 -#define _TO_BOOL_LIST_r02 1414 -#define _TO_BOOL_LIST_r12 1415 -#define _TO_BOOL_LIST_r23 1416 -#define _TO_BOOL_NONE_r01 1417 -#define _TO_BOOL_NONE_r11 1418 -#define _TO_BOOL_NONE_r22 1419 -#define _TO_BOOL_NONE_r33 1420 -#define _TO_BOOL_STR_r02 1421 -#define _TO_BOOL_STR_r12 1422 -#define _TO_BOOL_STR_r23 1423 -#define _TRACE_RECORD_r00 1424 -#define _UNARY_INVERT_r12 1425 -#define _UNARY_NEGATIVE_r12 1426 -#define _UNARY_NOT_r01 1427 -#define _UNARY_NOT_r11 1428 -#define _UNARY_NOT_r22 1429 -#define _UNARY_NOT_r33 1430 -#define _UNPACK_EX_r10 1431 -#define _UNPACK_SEQUENCE_r10 1432 -#define _UNPACK_SEQUENCE_LIST_r10 1433 -#define _UNPACK_SEQUENCE_TUPLE_r10 1434 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1435 -#define _WITH_EXCEPT_START_r33 1436 -#define _YIELD_VALUE_r11 1437 -#define MAX_UOP_REGS_ID 1437 +#define MAX_UOP_ID 581 +#define _BINARY_OP_r23 582 +#define _BINARY_OP_ADD_FLOAT_r03 583 +#define _BINARY_OP_ADD_FLOAT_r13 584 +#define _BINARY_OP_ADD_FLOAT_r23 585 +#define _BINARY_OP_ADD_INT_r03 586 +#define _BINARY_OP_ADD_INT_r13 587 +#define _BINARY_OP_ADD_INT_r23 588 +#define _BINARY_OP_ADD_UNICODE_r03 589 +#define _BINARY_OP_ADD_UNICODE_r13 590 +#define _BINARY_OP_ADD_UNICODE_r23 591 +#define _BINARY_OP_EXTEND_r23 592 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 593 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 594 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 595 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 596 +#define _BINARY_OP_MULTIPLY_INT_r03 597 +#define _BINARY_OP_MULTIPLY_INT_r13 598 +#define _BINARY_OP_MULTIPLY_INT_r23 599 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 600 +#define _BINARY_OP_SUBSCR_DICT_r23 601 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 602 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 603 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 604 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 605 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 606 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 607 +#define _BINARY_OP_SUBSCR_STR_INT_r23 608 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 609 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 610 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 611 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 612 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 613 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 614 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 615 +#define _BINARY_OP_SUBTRACT_INT_r03 616 +#define _BINARY_OP_SUBTRACT_INT_r13 617 +#define _BINARY_OP_SUBTRACT_INT_r23 618 +#define _BINARY_SLICE_r31 619 +#define _BUILD_INTERPOLATION_r01 620 +#define _BUILD_LIST_r01 621 +#define _BUILD_MAP_r01 622 +#define _BUILD_SET_r01 623 +#define _BUILD_SLICE_r01 624 +#define _BUILD_STRING_r01 625 +#define _BUILD_TEMPLATE_r21 626 +#define _BUILD_TUPLE_r01 627 +#define _CALL_BUILTIN_CLASS_r01 628 +#define _CALL_BUILTIN_FAST_r01 629 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 630 +#define _CALL_BUILTIN_O_r03 631 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 632 +#define _CALL_INTRINSIC_1_r11 633 +#define _CALL_INTRINSIC_2_r21 634 +#define _CALL_ISINSTANCE_r31 635 +#define _CALL_KW_NON_PY_r11 636 +#define _CALL_LEN_r33 637 +#define _CALL_LIST_APPEND_r03 638 +#define _CALL_LIST_APPEND_r13 639 +#define _CALL_LIST_APPEND_r23 640 +#define _CALL_LIST_APPEND_r33 641 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 642 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 643 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 644 +#define _CALL_METHOD_DESCRIPTOR_O_r03 645 +#define _CALL_NON_PY_GENERAL_r01 646 +#define _CALL_STR_1_r32 647 +#define _CALL_TUPLE_1_r32 648 +#define _CALL_TYPE_1_r02 649 +#define _CALL_TYPE_1_r12 650 +#define _CALL_TYPE_1_r22 651 +#define _CALL_TYPE_1_r32 652 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 653 +#define _CHECK_ATTR_CLASS_r01 654 +#define _CHECK_ATTR_CLASS_r11 655 +#define _CHECK_ATTR_CLASS_r22 656 +#define _CHECK_ATTR_CLASS_r33 657 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 658 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 659 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 660 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 661 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 662 +#define _CHECK_EG_MATCH_r22 663 +#define _CHECK_EXC_MATCH_r22 664 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 665 +#define _CHECK_FUNCTION_VERSION_r00 666 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 667 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 668 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 669 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 670 +#define _CHECK_FUNCTION_VERSION_KW_r11 671 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 672 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 673 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 674 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 675 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 676 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 677 +#define _CHECK_IS_PY_CALLABLE_EX_r03 678 +#define _CHECK_IS_PY_CALLABLE_EX_r13 679 +#define _CHECK_IS_PY_CALLABLE_EX_r23 680 +#define _CHECK_IS_PY_CALLABLE_EX_r33 681 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 682 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 683 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 684 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 685 +#define _CHECK_METHOD_VERSION_r00 686 +#define _CHECK_METHOD_VERSION_KW_r11 687 +#define _CHECK_PEP_523_r00 688 +#define _CHECK_PEP_523_r11 689 +#define _CHECK_PEP_523_r22 690 +#define _CHECK_PEP_523_r33 691 +#define _CHECK_PERIODIC_r00 692 +#define _CHECK_PERIODIC_AT_END_r00 693 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 694 +#define _CHECK_RECURSION_REMAINING_r00 695 +#define _CHECK_RECURSION_REMAINING_r11 696 +#define _CHECK_RECURSION_REMAINING_r22 697 +#define _CHECK_RECURSION_REMAINING_r33 698 +#define _CHECK_STACK_SPACE_r00 699 +#define _CHECK_STACK_SPACE_OPERAND_r00 700 +#define _CHECK_STACK_SPACE_OPERAND_r11 701 +#define _CHECK_STACK_SPACE_OPERAND_r22 702 +#define _CHECK_STACK_SPACE_OPERAND_r33 703 +#define _CHECK_VALIDITY_r00 704 +#define _CHECK_VALIDITY_r11 705 +#define _CHECK_VALIDITY_r22 706 +#define _CHECK_VALIDITY_r33 707 +#define _COLD_DYNAMIC_EXIT_r00 708 +#define _COLD_EXIT_r00 709 +#define _COMPARE_OP_r21 710 +#define _COMPARE_OP_FLOAT_r03 711 +#define _COMPARE_OP_FLOAT_r13 712 +#define _COMPARE_OP_FLOAT_r23 713 +#define _COMPARE_OP_INT_r23 714 +#define _COMPARE_OP_STR_r23 715 +#define _CONTAINS_OP_r23 716 +#define _CONTAINS_OP_DICT_r23 717 +#define _CONTAINS_OP_SET_r23 718 +#define _CONVERT_VALUE_r11 719 +#define _COPY_r01 720 +#define _COPY_1_r02 721 +#define _COPY_1_r12 722 +#define _COPY_1_r23 723 +#define _COPY_2_r03 724 +#define _COPY_2_r13 725 +#define _COPY_2_r23 726 +#define _COPY_3_r03 727 +#define _COPY_3_r13 728 +#define _COPY_3_r23 729 +#define _COPY_3_r33 730 +#define _COPY_FREE_VARS_r00 731 +#define _COPY_FREE_VARS_r11 732 +#define _COPY_FREE_VARS_r22 733 +#define _COPY_FREE_VARS_r33 734 +#define _CREATE_INIT_FRAME_r01 735 +#define _DELETE_ATTR_r10 736 +#define _DELETE_DEREF_r00 737 +#define _DELETE_FAST_r00 738 +#define _DELETE_GLOBAL_r00 739 +#define _DELETE_NAME_r00 740 +#define _DELETE_SUBSCR_r20 741 +#define _DEOPT_r00 742 +#define _DEOPT_r10 743 +#define _DEOPT_r20 744 +#define _DEOPT_r30 745 +#define _DICT_MERGE_r10 746 +#define _DICT_UPDATE_r10 747 +#define _DO_CALL_r01 748 +#define _DO_CALL_FUNCTION_EX_r31 749 +#define _DO_CALL_KW_r11 750 +#define _DYNAMIC_EXIT_r00 751 +#define _DYNAMIC_EXIT_r10 752 +#define _DYNAMIC_EXIT_r20 753 +#define _DYNAMIC_EXIT_r30 754 +#define _END_FOR_r10 755 +#define _END_SEND_r21 756 +#define _ERROR_POP_N_r00 757 +#define _EXIT_INIT_CHECK_r10 758 +#define _EXIT_TRACE_r00 759 +#define _EXIT_TRACE_r10 760 +#define _EXIT_TRACE_r20 761 +#define _EXIT_TRACE_r30 762 +#define _EXPAND_METHOD_r00 763 +#define _EXPAND_METHOD_KW_r11 764 +#define _FATAL_ERROR_r00 765 +#define _FATAL_ERROR_r11 766 +#define _FATAL_ERROR_r22 767 +#define _FATAL_ERROR_r33 768 +#define _FORMAT_SIMPLE_r11 769 +#define _FORMAT_WITH_SPEC_r21 770 +#define _FOR_ITER_r23 771 +#define _FOR_ITER_GEN_FRAME_r03 772 +#define _FOR_ITER_GEN_FRAME_r13 773 +#define _FOR_ITER_GEN_FRAME_r23 774 +#define _FOR_ITER_TIER_TWO_r23 775 +#define _GET_AITER_r11 776 +#define _GET_ANEXT_r12 777 +#define _GET_AWAITABLE_r11 778 +#define _GET_ITER_r12 779 +#define _GET_LEN_r12 780 +#define _GET_YIELD_FROM_ITER_r11 781 +#define _GUARD_BINARY_OP_EXTEND_r22 782 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 783 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 784 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 785 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 786 +#define _GUARD_BIT_IS_SET_POP_r00 787 +#define _GUARD_BIT_IS_SET_POP_r10 788 +#define _GUARD_BIT_IS_SET_POP_r21 789 +#define _GUARD_BIT_IS_SET_POP_r32 790 +#define _GUARD_BIT_IS_SET_POP_4_r00 791 +#define _GUARD_BIT_IS_SET_POP_4_r10 792 +#define _GUARD_BIT_IS_SET_POP_4_r21 793 +#define _GUARD_BIT_IS_SET_POP_4_r32 794 +#define _GUARD_BIT_IS_SET_POP_5_r00 795 +#define _GUARD_BIT_IS_SET_POP_5_r10 796 +#define _GUARD_BIT_IS_SET_POP_5_r21 797 +#define _GUARD_BIT_IS_SET_POP_5_r32 798 +#define _GUARD_BIT_IS_SET_POP_6_r00 799 +#define _GUARD_BIT_IS_SET_POP_6_r10 800 +#define _GUARD_BIT_IS_SET_POP_6_r21 801 +#define _GUARD_BIT_IS_SET_POP_6_r32 802 +#define _GUARD_BIT_IS_SET_POP_7_r00 803 +#define _GUARD_BIT_IS_SET_POP_7_r10 804 +#define _GUARD_BIT_IS_SET_POP_7_r21 805 +#define _GUARD_BIT_IS_SET_POP_7_r32 806 +#define _GUARD_BIT_IS_UNSET_POP_r00 807 +#define _GUARD_BIT_IS_UNSET_POP_r10 808 +#define _GUARD_BIT_IS_UNSET_POP_r21 809 +#define _GUARD_BIT_IS_UNSET_POP_r32 810 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 811 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 812 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 813 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 814 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 815 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 816 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 817 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 818 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 819 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 820 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 821 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 822 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 823 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 824 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 825 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 826 +#define _GUARD_CALLABLE_ISINSTANCE_r03 827 +#define _GUARD_CALLABLE_ISINSTANCE_r13 828 +#define _GUARD_CALLABLE_ISINSTANCE_r23 829 +#define _GUARD_CALLABLE_ISINSTANCE_r33 830 +#define _GUARD_CALLABLE_LEN_r03 831 +#define _GUARD_CALLABLE_LEN_r13 832 +#define _GUARD_CALLABLE_LEN_r23 833 +#define _GUARD_CALLABLE_LEN_r33 834 +#define _GUARD_CALLABLE_LIST_APPEND_r03 835 +#define _GUARD_CALLABLE_LIST_APPEND_r13 836 +#define _GUARD_CALLABLE_LIST_APPEND_r23 837 +#define _GUARD_CALLABLE_LIST_APPEND_r33 838 +#define _GUARD_CALLABLE_STR_1_r03 839 +#define _GUARD_CALLABLE_STR_1_r13 840 +#define _GUARD_CALLABLE_STR_1_r23 841 +#define _GUARD_CALLABLE_STR_1_r33 842 +#define _GUARD_CALLABLE_TUPLE_1_r03 843 +#define _GUARD_CALLABLE_TUPLE_1_r13 844 +#define _GUARD_CALLABLE_TUPLE_1_r23 845 +#define _GUARD_CALLABLE_TUPLE_1_r33 846 +#define _GUARD_CALLABLE_TYPE_1_r03 847 +#define _GUARD_CALLABLE_TYPE_1_r13 848 +#define _GUARD_CALLABLE_TYPE_1_r23 849 +#define _GUARD_CALLABLE_TYPE_1_r33 850 +#define _GUARD_DORV_NO_DICT_r01 851 +#define _GUARD_DORV_NO_DICT_r11 852 +#define _GUARD_DORV_NO_DICT_r22 853 +#define _GUARD_DORV_NO_DICT_r33 854 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 855 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 856 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 857 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 858 +#define _GUARD_GLOBALS_VERSION_r00 859 +#define _GUARD_GLOBALS_VERSION_r11 860 +#define _GUARD_GLOBALS_VERSION_r22 861 +#define _GUARD_GLOBALS_VERSION_r33 862 +#define _GUARD_IP_RETURN_GENERATOR_r00 863 +#define _GUARD_IP_RETURN_GENERATOR_r11 864 +#define _GUARD_IP_RETURN_GENERATOR_r22 865 +#define _GUARD_IP_RETURN_GENERATOR_r33 866 +#define _GUARD_IP_RETURN_VALUE_r00 867 +#define _GUARD_IP_RETURN_VALUE_r11 868 +#define _GUARD_IP_RETURN_VALUE_r22 869 +#define _GUARD_IP_RETURN_VALUE_r33 870 +#define _GUARD_IP_YIELD_VALUE_r00 871 +#define _GUARD_IP_YIELD_VALUE_r11 872 +#define _GUARD_IP_YIELD_VALUE_r22 873 +#define _GUARD_IP_YIELD_VALUE_r33 874 +#define _GUARD_IP__PUSH_FRAME_r00 875 +#define _GUARD_IP__PUSH_FRAME_r11 876 +#define _GUARD_IP__PUSH_FRAME_r22 877 +#define _GUARD_IP__PUSH_FRAME_r33 878 +#define _GUARD_IS_FALSE_POP_r00 879 +#define _GUARD_IS_FALSE_POP_r10 880 +#define _GUARD_IS_FALSE_POP_r21 881 +#define _GUARD_IS_FALSE_POP_r32 882 +#define _GUARD_IS_NONE_POP_r00 883 +#define _GUARD_IS_NONE_POP_r10 884 +#define _GUARD_IS_NONE_POP_r21 885 +#define _GUARD_IS_NONE_POP_r32 886 +#define _GUARD_IS_NOT_NONE_POP_r10 887 +#define _GUARD_IS_TRUE_POP_r00 888 +#define _GUARD_IS_TRUE_POP_r10 889 +#define _GUARD_IS_TRUE_POP_r21 890 +#define _GUARD_IS_TRUE_POP_r32 891 +#define _GUARD_KEYS_VERSION_r01 892 +#define _GUARD_KEYS_VERSION_r11 893 +#define _GUARD_KEYS_VERSION_r22 894 +#define _GUARD_KEYS_VERSION_r33 895 +#define _GUARD_NOS_COMPACT_ASCII_r02 896 +#define _GUARD_NOS_COMPACT_ASCII_r12 897 +#define _GUARD_NOS_COMPACT_ASCII_r22 898 +#define _GUARD_NOS_COMPACT_ASCII_r33 899 +#define _GUARD_NOS_DICT_r02 900 +#define _GUARD_NOS_DICT_r12 901 +#define _GUARD_NOS_DICT_r22 902 +#define _GUARD_NOS_DICT_r33 903 +#define _GUARD_NOS_FLOAT_r02 904 +#define _GUARD_NOS_FLOAT_r12 905 +#define _GUARD_NOS_FLOAT_r22 906 +#define _GUARD_NOS_FLOAT_r33 907 +#define _GUARD_NOS_INT_r02 908 +#define _GUARD_NOS_INT_r12 909 +#define _GUARD_NOS_INT_r22 910 +#define _GUARD_NOS_INT_r33 911 +#define _GUARD_NOS_LIST_r02 912 +#define _GUARD_NOS_LIST_r12 913 +#define _GUARD_NOS_LIST_r22 914 +#define _GUARD_NOS_LIST_r33 915 +#define _GUARD_NOS_NOT_NULL_r02 916 +#define _GUARD_NOS_NOT_NULL_r12 917 +#define _GUARD_NOS_NOT_NULL_r22 918 +#define _GUARD_NOS_NOT_NULL_r33 919 +#define _GUARD_NOS_NULL_r02 920 +#define _GUARD_NOS_NULL_r12 921 +#define _GUARD_NOS_NULL_r22 922 +#define _GUARD_NOS_NULL_r33 923 +#define _GUARD_NOS_OVERFLOWED_r02 924 +#define _GUARD_NOS_OVERFLOWED_r12 925 +#define _GUARD_NOS_OVERFLOWED_r22 926 +#define _GUARD_NOS_OVERFLOWED_r33 927 +#define _GUARD_NOS_TUPLE_r02 928 +#define _GUARD_NOS_TUPLE_r12 929 +#define _GUARD_NOS_TUPLE_r22 930 +#define _GUARD_NOS_TUPLE_r33 931 +#define _GUARD_NOS_UNICODE_r02 932 +#define _GUARD_NOS_UNICODE_r12 933 +#define _GUARD_NOS_UNICODE_r22 934 +#define _GUARD_NOS_UNICODE_r33 935 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 936 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 937 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 938 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 939 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 940 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 941 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 942 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 943 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 944 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 945 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 946 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 947 +#define _GUARD_THIRD_NULL_r03 948 +#define _GUARD_THIRD_NULL_r13 949 +#define _GUARD_THIRD_NULL_r23 950 +#define _GUARD_THIRD_NULL_r33 951 +#define _GUARD_TOS_ANY_SET_r01 952 +#define _GUARD_TOS_ANY_SET_r11 953 +#define _GUARD_TOS_ANY_SET_r22 954 +#define _GUARD_TOS_ANY_SET_r33 955 +#define _GUARD_TOS_DICT_r01 956 +#define _GUARD_TOS_DICT_r11 957 +#define _GUARD_TOS_DICT_r22 958 +#define _GUARD_TOS_DICT_r33 959 +#define _GUARD_TOS_FLOAT_r01 960 +#define _GUARD_TOS_FLOAT_r11 961 +#define _GUARD_TOS_FLOAT_r22 962 +#define _GUARD_TOS_FLOAT_r33 963 +#define _GUARD_TOS_INT_r01 964 +#define _GUARD_TOS_INT_r11 965 +#define _GUARD_TOS_INT_r22 966 +#define _GUARD_TOS_INT_r33 967 +#define _GUARD_TOS_LIST_r01 968 +#define _GUARD_TOS_LIST_r11 969 +#define _GUARD_TOS_LIST_r22 970 +#define _GUARD_TOS_LIST_r33 971 +#define _GUARD_TOS_OVERFLOWED_r01 972 +#define _GUARD_TOS_OVERFLOWED_r11 973 +#define _GUARD_TOS_OVERFLOWED_r22 974 +#define _GUARD_TOS_OVERFLOWED_r33 975 +#define _GUARD_TOS_SLICE_r01 976 +#define _GUARD_TOS_SLICE_r11 977 +#define _GUARD_TOS_SLICE_r22 978 +#define _GUARD_TOS_SLICE_r33 979 +#define _GUARD_TOS_TUPLE_r01 980 +#define _GUARD_TOS_TUPLE_r11 981 +#define _GUARD_TOS_TUPLE_r22 982 +#define _GUARD_TOS_TUPLE_r33 983 +#define _GUARD_TOS_UNICODE_r01 984 +#define _GUARD_TOS_UNICODE_r11 985 +#define _GUARD_TOS_UNICODE_r22 986 +#define _GUARD_TOS_UNICODE_r33 987 +#define _GUARD_TYPE_VERSION_r01 988 +#define _GUARD_TYPE_VERSION_r11 989 +#define _GUARD_TYPE_VERSION_r22 990 +#define _GUARD_TYPE_VERSION_r33 991 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 992 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 993 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 994 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 995 +#define _HANDLE_PENDING_AND_DEOPT_r00 996 +#define _HANDLE_PENDING_AND_DEOPT_r10 997 +#define _HANDLE_PENDING_AND_DEOPT_r20 998 +#define _HANDLE_PENDING_AND_DEOPT_r30 999 +#define _IMPORT_FROM_r12 1000 +#define _IMPORT_NAME_r21 1001 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1002 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1003 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1004 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1005 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1006 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1007 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1008 +#define _INSERT_1_LOAD_CONST_INLINE_r02 1009 +#define _INSERT_1_LOAD_CONST_INLINE_r12 1010 +#define _INSERT_1_LOAD_CONST_INLINE_r23 1011 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1012 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1013 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1014 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1015 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1016 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1017 +#define _INSERT_NULL_r10 1018 +#define _INSTRUMENTED_FOR_ITER_r23 1019 +#define _INSTRUMENTED_INSTRUCTION_r00 1020 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1021 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1022 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1023 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1024 +#define _INSTRUMENTED_LINE_r00 1025 +#define _INSTRUMENTED_NOT_TAKEN_r00 1026 +#define _INSTRUMENTED_NOT_TAKEN_r11 1027 +#define _INSTRUMENTED_NOT_TAKEN_r22 1028 +#define _INSTRUMENTED_NOT_TAKEN_r33 1029 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1030 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1031 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1032 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1033 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1034 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1035 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1036 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1037 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1038 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1039 +#define _IS_NONE_r11 1040 +#define _IS_OP_r03 1041 +#define _IS_OP_r13 1042 +#define _IS_OP_r23 1043 +#define _ITER_CHECK_LIST_r02 1044 +#define _ITER_CHECK_LIST_r12 1045 +#define _ITER_CHECK_LIST_r22 1046 +#define _ITER_CHECK_LIST_r33 1047 +#define _ITER_CHECK_RANGE_r02 1048 +#define _ITER_CHECK_RANGE_r12 1049 +#define _ITER_CHECK_RANGE_r22 1050 +#define _ITER_CHECK_RANGE_r33 1051 +#define _ITER_CHECK_TUPLE_r02 1052 +#define _ITER_CHECK_TUPLE_r12 1053 +#define _ITER_CHECK_TUPLE_r22 1054 +#define _ITER_CHECK_TUPLE_r33 1055 +#define _ITER_JUMP_LIST_r02 1056 +#define _ITER_JUMP_LIST_r12 1057 +#define _ITER_JUMP_LIST_r22 1058 +#define _ITER_JUMP_LIST_r33 1059 +#define _ITER_JUMP_RANGE_r02 1060 +#define _ITER_JUMP_RANGE_r12 1061 +#define _ITER_JUMP_RANGE_r22 1062 +#define _ITER_JUMP_RANGE_r33 1063 +#define _ITER_JUMP_TUPLE_r02 1064 +#define _ITER_JUMP_TUPLE_r12 1065 +#define _ITER_JUMP_TUPLE_r22 1066 +#define _ITER_JUMP_TUPLE_r33 1067 +#define _ITER_NEXT_LIST_r23 1068 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1069 +#define _ITER_NEXT_RANGE_r03 1070 +#define _ITER_NEXT_RANGE_r13 1071 +#define _ITER_NEXT_RANGE_r23 1072 +#define _ITER_NEXT_TUPLE_r03 1073 +#define _ITER_NEXT_TUPLE_r13 1074 +#define _ITER_NEXT_TUPLE_r23 1075 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1076 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1077 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1078 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1079 +#define _JUMP_TO_TOP_r00 1080 +#define _LIST_APPEND_r10 1081 +#define _LIST_EXTEND_r10 1082 +#define _LOAD_ATTR_r10 1083 +#define _LOAD_ATTR_CLASS_r11 1084 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1085 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1086 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1087 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1088 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1089 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1090 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1091 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1092 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1093 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1094 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1095 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1096 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1097 +#define _LOAD_ATTR_MODULE_r12 1098 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1099 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1100 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1101 +#define _LOAD_ATTR_SLOT_r02 1102 +#define _LOAD_ATTR_SLOT_r12 1103 +#define _LOAD_ATTR_SLOT_r23 1104 +#define _LOAD_ATTR_WITH_HINT_r12 1105 +#define _LOAD_BUILD_CLASS_r01 1106 +#define _LOAD_BYTECODE_r00 1107 +#define _LOAD_COMMON_CONSTANT_r01 1108 +#define _LOAD_COMMON_CONSTANT_r12 1109 +#define _LOAD_COMMON_CONSTANT_r23 1110 +#define _LOAD_CONST_r01 1111 +#define _LOAD_CONST_r12 1112 +#define _LOAD_CONST_r23 1113 +#define _LOAD_CONST_INLINE_r01 1114 +#define _LOAD_CONST_INLINE_r12 1115 +#define _LOAD_CONST_INLINE_r23 1116 +#define _LOAD_CONST_INLINE_BORROW_r01 1117 +#define _LOAD_CONST_INLINE_BORROW_r12 1118 +#define _LOAD_CONST_INLINE_BORROW_r23 1119 +#define _LOAD_CONST_UNDER_INLINE_r02 1120 +#define _LOAD_CONST_UNDER_INLINE_r12 1121 +#define _LOAD_CONST_UNDER_INLINE_r23 1122 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1123 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1124 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1125 +#define _LOAD_DEREF_r01 1126 +#define _LOAD_FAST_r01 1127 +#define _LOAD_FAST_r12 1128 +#define _LOAD_FAST_r23 1129 +#define _LOAD_FAST_0_r01 1130 +#define _LOAD_FAST_0_r12 1131 +#define _LOAD_FAST_0_r23 1132 +#define _LOAD_FAST_1_r01 1133 +#define _LOAD_FAST_1_r12 1134 +#define _LOAD_FAST_1_r23 1135 +#define _LOAD_FAST_2_r01 1136 +#define _LOAD_FAST_2_r12 1137 +#define _LOAD_FAST_2_r23 1138 +#define _LOAD_FAST_3_r01 1139 +#define _LOAD_FAST_3_r12 1140 +#define _LOAD_FAST_3_r23 1141 +#define _LOAD_FAST_4_r01 1142 +#define _LOAD_FAST_4_r12 1143 +#define _LOAD_FAST_4_r23 1144 +#define _LOAD_FAST_5_r01 1145 +#define _LOAD_FAST_5_r12 1146 +#define _LOAD_FAST_5_r23 1147 +#define _LOAD_FAST_6_r01 1148 +#define _LOAD_FAST_6_r12 1149 +#define _LOAD_FAST_6_r23 1150 +#define _LOAD_FAST_7_r01 1151 +#define _LOAD_FAST_7_r12 1152 +#define _LOAD_FAST_7_r23 1153 +#define _LOAD_FAST_AND_CLEAR_r01 1154 +#define _LOAD_FAST_AND_CLEAR_r12 1155 +#define _LOAD_FAST_AND_CLEAR_r23 1156 +#define _LOAD_FAST_BORROW_r01 1157 +#define _LOAD_FAST_BORROW_r12 1158 +#define _LOAD_FAST_BORROW_r23 1159 +#define _LOAD_FAST_BORROW_0_r01 1160 +#define _LOAD_FAST_BORROW_0_r12 1161 +#define _LOAD_FAST_BORROW_0_r23 1162 +#define _LOAD_FAST_BORROW_1_r01 1163 +#define _LOAD_FAST_BORROW_1_r12 1164 +#define _LOAD_FAST_BORROW_1_r23 1165 +#define _LOAD_FAST_BORROW_2_r01 1166 +#define _LOAD_FAST_BORROW_2_r12 1167 +#define _LOAD_FAST_BORROW_2_r23 1168 +#define _LOAD_FAST_BORROW_3_r01 1169 +#define _LOAD_FAST_BORROW_3_r12 1170 +#define _LOAD_FAST_BORROW_3_r23 1171 +#define _LOAD_FAST_BORROW_4_r01 1172 +#define _LOAD_FAST_BORROW_4_r12 1173 +#define _LOAD_FAST_BORROW_4_r23 1174 +#define _LOAD_FAST_BORROW_5_r01 1175 +#define _LOAD_FAST_BORROW_5_r12 1176 +#define _LOAD_FAST_BORROW_5_r23 1177 +#define _LOAD_FAST_BORROW_6_r01 1178 +#define _LOAD_FAST_BORROW_6_r12 1179 +#define _LOAD_FAST_BORROW_6_r23 1180 +#define _LOAD_FAST_BORROW_7_r01 1181 +#define _LOAD_FAST_BORROW_7_r12 1182 +#define _LOAD_FAST_BORROW_7_r23 1183 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1184 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1185 +#define _LOAD_FAST_CHECK_r01 1186 +#define _LOAD_FAST_CHECK_r12 1187 +#define _LOAD_FAST_CHECK_r23 1188 +#define _LOAD_FAST_LOAD_FAST_r02 1189 +#define _LOAD_FAST_LOAD_FAST_r13 1190 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1191 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1192 +#define _LOAD_GLOBAL_r00 1193 +#define _LOAD_GLOBAL_BUILTINS_r01 1194 +#define _LOAD_GLOBAL_MODULE_r01 1195 +#define _LOAD_LOCALS_r01 1196 +#define _LOAD_LOCALS_r12 1197 +#define _LOAD_LOCALS_r23 1198 +#define _LOAD_NAME_r01 1199 +#define _LOAD_SMALL_INT_r01 1200 +#define _LOAD_SMALL_INT_r12 1201 +#define _LOAD_SMALL_INT_r23 1202 +#define _LOAD_SMALL_INT_0_r01 1203 +#define _LOAD_SMALL_INT_0_r12 1204 +#define _LOAD_SMALL_INT_0_r23 1205 +#define _LOAD_SMALL_INT_1_r01 1206 +#define _LOAD_SMALL_INT_1_r12 1207 +#define _LOAD_SMALL_INT_1_r23 1208 +#define _LOAD_SMALL_INT_2_r01 1209 +#define _LOAD_SMALL_INT_2_r12 1210 +#define _LOAD_SMALL_INT_2_r23 1211 +#define _LOAD_SMALL_INT_3_r01 1212 +#define _LOAD_SMALL_INT_3_r12 1213 +#define _LOAD_SMALL_INT_3_r23 1214 +#define _LOAD_SPECIAL_r00 1215 +#define _LOAD_SUPER_ATTR_ATTR_r31 1216 +#define _LOAD_SUPER_ATTR_METHOD_r32 1217 +#define _MAKE_CALLARGS_A_TUPLE_r33 1218 +#define _MAKE_CELL_r00 1219 +#define _MAKE_FUNCTION_r11 1220 +#define _MAKE_WARM_r00 1221 +#define _MAKE_WARM_r11 1222 +#define _MAKE_WARM_r22 1223 +#define _MAKE_WARM_r33 1224 +#define _MAP_ADD_r20 1225 +#define _MATCH_CLASS_r31 1226 +#define _MATCH_KEYS_r23 1227 +#define _MATCH_MAPPING_r02 1228 +#define _MATCH_MAPPING_r12 1229 +#define _MATCH_MAPPING_r23 1230 +#define _MATCH_SEQUENCE_r02 1231 +#define _MATCH_SEQUENCE_r12 1232 +#define _MATCH_SEQUENCE_r23 1233 +#define _MAYBE_EXPAND_METHOD_r00 1234 +#define _MAYBE_EXPAND_METHOD_KW_r11 1235 +#define _MONITOR_CALL_r00 1236 +#define _MONITOR_CALL_KW_r11 1237 +#define _MONITOR_JUMP_BACKWARD_r00 1238 +#define _MONITOR_JUMP_BACKWARD_r11 1239 +#define _MONITOR_JUMP_BACKWARD_r22 1240 +#define _MONITOR_JUMP_BACKWARD_r33 1241 +#define _MONITOR_RESUME_r00 1242 +#define _NOP_r00 1243 +#define _NOP_r11 1244 +#define _NOP_r22 1245 +#define _NOP_r33 1246 +#define _POP_CALL_r20 1247 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1248 +#define _POP_CALL_ONE_r30 1249 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1250 +#define _POP_CALL_TWO_r30 1251 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1252 +#define _POP_EXCEPT_r10 1253 +#define _POP_ITER_r20 1254 +#define _POP_JUMP_IF_FALSE_r00 1255 +#define _POP_JUMP_IF_FALSE_r10 1256 +#define _POP_JUMP_IF_FALSE_r21 1257 +#define _POP_JUMP_IF_FALSE_r32 1258 +#define _POP_JUMP_IF_TRUE_r00 1259 +#define _POP_JUMP_IF_TRUE_r10 1260 +#define _POP_JUMP_IF_TRUE_r21 1261 +#define _POP_JUMP_IF_TRUE_r32 1262 +#define _POP_TOP_r10 1263 +#define _POP_TOP_FLOAT_r00 1264 +#define _POP_TOP_FLOAT_r10 1265 +#define _POP_TOP_FLOAT_r21 1266 +#define _POP_TOP_FLOAT_r32 1267 +#define _POP_TOP_INT_r00 1268 +#define _POP_TOP_INT_r10 1269 +#define _POP_TOP_INT_r21 1270 +#define _POP_TOP_INT_r32 1271 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1272 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1273 +#define _POP_TOP_NOP_r00 1274 +#define _POP_TOP_NOP_r10 1275 +#define _POP_TOP_NOP_r21 1276 +#define _POP_TOP_NOP_r32 1277 +#define _POP_TOP_UNICODE_r00 1278 +#define _POP_TOP_UNICODE_r10 1279 +#define _POP_TOP_UNICODE_r21 1280 +#define _POP_TOP_UNICODE_r32 1281 +#define _POP_TWO_r20 1282 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1283 +#define _PUSH_EXC_INFO_r02 1284 +#define _PUSH_EXC_INFO_r12 1285 +#define _PUSH_EXC_INFO_r23 1286 +#define _PUSH_FRAME_r10 1287 +#define _PUSH_NULL_r01 1288 +#define _PUSH_NULL_r12 1289 +#define _PUSH_NULL_r23 1290 +#define _PUSH_NULL_CONDITIONAL_r00 1291 +#define _PY_FRAME_EX_r31 1292 +#define _PY_FRAME_GENERAL_r01 1293 +#define _PY_FRAME_KW_r11 1294 +#define _QUICKEN_RESUME_r00 1295 +#define _QUICKEN_RESUME_r11 1296 +#define _QUICKEN_RESUME_r22 1297 +#define _QUICKEN_RESUME_r33 1298 +#define _REPLACE_WITH_TRUE_r02 1299 +#define _REPLACE_WITH_TRUE_r12 1300 +#define _REPLACE_WITH_TRUE_r23 1301 +#define _RESUME_CHECK_r00 1302 +#define _RESUME_CHECK_r11 1303 +#define _RESUME_CHECK_r22 1304 +#define _RESUME_CHECK_r33 1305 +#define _RETURN_GENERATOR_r01 1306 +#define _RETURN_VALUE_r11 1307 +#define _SAVE_RETURN_OFFSET_r00 1308 +#define _SAVE_RETURN_OFFSET_r11 1309 +#define _SAVE_RETURN_OFFSET_r22 1310 +#define _SAVE_RETURN_OFFSET_r33 1311 +#define _SEND_r22 1312 +#define _SEND_GEN_FRAME_r22 1313 +#define _SETUP_ANNOTATIONS_r00 1314 +#define _SET_ADD_r10 1315 +#define _SET_FUNCTION_ATTRIBUTE_r01 1316 +#define _SET_FUNCTION_ATTRIBUTE_r11 1317 +#define _SET_FUNCTION_ATTRIBUTE_r21 1318 +#define _SET_FUNCTION_ATTRIBUTE_r32 1319 +#define _SET_IP_r00 1320 +#define _SET_IP_r11 1321 +#define _SET_IP_r22 1322 +#define _SET_IP_r33 1323 +#define _SET_UPDATE_r10 1324 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1325 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1326 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1327 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1328 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1329 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1330 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1331 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1332 +#define _SPILL_OR_RELOAD_r01 1333 +#define _SPILL_OR_RELOAD_r02 1334 +#define _SPILL_OR_RELOAD_r03 1335 +#define _SPILL_OR_RELOAD_r10 1336 +#define _SPILL_OR_RELOAD_r12 1337 +#define _SPILL_OR_RELOAD_r13 1338 +#define _SPILL_OR_RELOAD_r20 1339 +#define _SPILL_OR_RELOAD_r21 1340 +#define _SPILL_OR_RELOAD_r23 1341 +#define _SPILL_OR_RELOAD_r30 1342 +#define _SPILL_OR_RELOAD_r31 1343 +#define _SPILL_OR_RELOAD_r32 1344 +#define _START_EXECUTOR_r00 1345 +#define _STORE_ATTR_r20 1346 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1347 +#define _STORE_ATTR_INSTANCE_VALUE_NULL_r01 1348 +#define _STORE_ATTR_INSTANCE_VALUE_NULL_r11 1349 +#define _STORE_ATTR_INSTANCE_VALUE_NULL_r21 1350 +#define _STORE_ATTR_INSTANCE_VALUE_NULL_r32 1351 +#define _STORE_ATTR_SLOT_r21 1352 +#define _STORE_ATTR_SLOT_NULL_r01 1353 +#define _STORE_ATTR_SLOT_NULL_r11 1354 +#define _STORE_ATTR_SLOT_NULL_r21 1355 +#define _STORE_ATTR_SLOT_NULL_r32 1356 +#define _STORE_ATTR_WITH_HINT_r21 1357 +#define _STORE_DEREF_r10 1358 +#define _STORE_FAST_LOAD_FAST_r11 1359 +#define _STORE_FAST_STORE_FAST_r20 1360 +#define _STORE_GLOBAL_r10 1361 +#define _STORE_NAME_r10 1362 +#define _STORE_SLICE_r30 1363 +#define _STORE_SUBSCR_r30 1364 +#define _STORE_SUBSCR_DICT_r31 1365 +#define _STORE_SUBSCR_LIST_INT_r32 1366 +#define _SWAP_r11 1367 +#define _SWAP_2_r02 1368 +#define _SWAP_2_r12 1369 +#define _SWAP_2_r22 1370 +#define _SWAP_2_r33 1371 +#define _SWAP_3_r03 1372 +#define _SWAP_3_r13 1373 +#define _SWAP_3_r23 1374 +#define _SWAP_3_r33 1375 +#define _SWAP_FAST_r01 1376 +#define _SWAP_FAST_r11 1377 +#define _SWAP_FAST_r22 1378 +#define _SWAP_FAST_r33 1379 +#define _SWAP_FAST_0_r01 1380 +#define _SWAP_FAST_0_r11 1381 +#define _SWAP_FAST_0_r22 1382 +#define _SWAP_FAST_0_r33 1383 +#define _SWAP_FAST_1_r01 1384 +#define _SWAP_FAST_1_r11 1385 +#define _SWAP_FAST_1_r22 1386 +#define _SWAP_FAST_1_r33 1387 +#define _SWAP_FAST_2_r01 1388 +#define _SWAP_FAST_2_r11 1389 +#define _SWAP_FAST_2_r22 1390 +#define _SWAP_FAST_2_r33 1391 +#define _SWAP_FAST_3_r01 1392 +#define _SWAP_FAST_3_r11 1393 +#define _SWAP_FAST_3_r22 1394 +#define _SWAP_FAST_3_r33 1395 +#define _SWAP_FAST_4_r01 1396 +#define _SWAP_FAST_4_r11 1397 +#define _SWAP_FAST_4_r22 1398 +#define _SWAP_FAST_4_r33 1399 +#define _SWAP_FAST_5_r01 1400 +#define _SWAP_FAST_5_r11 1401 +#define _SWAP_FAST_5_r22 1402 +#define _SWAP_FAST_5_r33 1403 +#define _SWAP_FAST_6_r01 1404 +#define _SWAP_FAST_6_r11 1405 +#define _SWAP_FAST_6_r22 1406 +#define _SWAP_FAST_6_r33 1407 +#define _SWAP_FAST_7_r01 1408 +#define _SWAP_FAST_7_r11 1409 +#define _SWAP_FAST_7_r22 1410 +#define _SWAP_FAST_7_r33 1411 +#define _TIER2_RESUME_CHECK_r00 1412 +#define _TIER2_RESUME_CHECK_r11 1413 +#define _TIER2_RESUME_CHECK_r22 1414 +#define _TIER2_RESUME_CHECK_r33 1415 +#define _TO_BOOL_r11 1416 +#define _TO_BOOL_BOOL_r01 1417 +#define _TO_BOOL_BOOL_r11 1418 +#define _TO_BOOL_BOOL_r22 1419 +#define _TO_BOOL_BOOL_r33 1420 +#define _TO_BOOL_INT_r02 1421 +#define _TO_BOOL_INT_r12 1422 +#define _TO_BOOL_INT_r23 1423 +#define _TO_BOOL_LIST_r02 1424 +#define _TO_BOOL_LIST_r12 1425 +#define _TO_BOOL_LIST_r23 1426 +#define _TO_BOOL_NONE_r01 1427 +#define _TO_BOOL_NONE_r11 1428 +#define _TO_BOOL_NONE_r22 1429 +#define _TO_BOOL_NONE_r33 1430 +#define _TO_BOOL_STR_r02 1431 +#define _TO_BOOL_STR_r12 1432 +#define _TO_BOOL_STR_r23 1433 +#define _TRACE_RECORD_r00 1434 +#define _UNARY_INVERT_r12 1435 +#define _UNARY_NEGATIVE_r12 1436 +#define _UNARY_NOT_r01 1437 +#define _UNARY_NOT_r11 1438 +#define _UNARY_NOT_r22 1439 +#define _UNARY_NOT_r33 1440 +#define _UNPACK_EX_r10 1441 +#define _UNPACK_SEQUENCE_r10 1442 +#define _UNPACK_SEQUENCE_LIST_r10 1443 +#define _UNPACK_SEQUENCE_TUPLE_r10 1444 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1445 +#define _WITH_EXCEPT_START_r33 1446 +#define _YIELD_VALUE_r11 1447 +#define MAX_UOP_REGS_ID 1447 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 07c4f0aeb4a..d19f219c165 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -201,8 +201,10 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_GUARD_DORV_NO_DICT] = HAS_EXIT_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, + [_STORE_ATTR_INSTANCE_VALUE_NULL] = HAS_DEOPT_FLAG, [_STORE_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_STORE_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, + [_STORE_ATTR_SLOT_NULL] = HAS_DEOPT_FLAG, [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG, [_COMPARE_OP_INT] = HAS_ARG_FLAG, @@ -1883,6 +1885,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, + [_STORE_ATTR_INSTANCE_VALUE_NULL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _STORE_ATTR_INSTANCE_VALUE_NULL_r01 }, + { 1, 1, _STORE_ATTR_INSTANCE_VALUE_NULL_r11 }, + { 1, 2, _STORE_ATTR_INSTANCE_VALUE_NULL_r21 }, + { 2, 3, _STORE_ATTR_INSTANCE_VALUE_NULL_r32 }, + }, + }, [_STORE_ATTR_WITH_HINT] = { .best = { 2, 2, 2, 2 }, .entries = { @@ -1901,6 +1912,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, + [_STORE_ATTR_SLOT_NULL] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 1, 0, _STORE_ATTR_SLOT_NULL_r01 }, + { 1, 1, _STORE_ATTR_SLOT_NULL_r11 }, + { 1, 2, _STORE_ATTR_SLOT_NULL_r21 }, + { 2, 3, _STORE_ATTR_SLOT_NULL_r32 }, + }, + }, [_COMPARE_OP] = { .best = { 2, 2, 2, 2 }, .entries = { @@ -3815,8 +3835,16 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_GUARD_DORV_NO_DICT_r22] = _GUARD_DORV_NO_DICT, [_GUARD_DORV_NO_DICT_r33] = _GUARD_DORV_NO_DICT, [_STORE_ATTR_INSTANCE_VALUE_r21] = _STORE_ATTR_INSTANCE_VALUE, + [_STORE_ATTR_INSTANCE_VALUE_NULL_r01] = _STORE_ATTR_INSTANCE_VALUE_NULL, + [_STORE_ATTR_INSTANCE_VALUE_NULL_r11] = _STORE_ATTR_INSTANCE_VALUE_NULL, + [_STORE_ATTR_INSTANCE_VALUE_NULL_r21] = _STORE_ATTR_INSTANCE_VALUE_NULL, + [_STORE_ATTR_INSTANCE_VALUE_NULL_r32] = _STORE_ATTR_INSTANCE_VALUE_NULL, [_STORE_ATTR_WITH_HINT_r21] = _STORE_ATTR_WITH_HINT, [_STORE_ATTR_SLOT_r21] = _STORE_ATTR_SLOT, + [_STORE_ATTR_SLOT_NULL_r01] = _STORE_ATTR_SLOT_NULL, + [_STORE_ATTR_SLOT_NULL_r11] = _STORE_ATTR_SLOT_NULL, + [_STORE_ATTR_SLOT_NULL_r21] = _STORE_ATTR_SLOT_NULL, + [_STORE_ATTR_SLOT_NULL_r32] = _STORE_ATTR_SLOT_NULL, [_COMPARE_OP_r21] = _COMPARE_OP, [_COMPARE_OP_FLOAT_r03] = _COMPARE_OP_FLOAT, [_COMPARE_OP_FLOAT_r13] = _COMPARE_OP_FLOAT, @@ -5234,8 +5262,18 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_STORE_ATTR_r20] = "_STORE_ATTR_r20", [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", [_STORE_ATTR_INSTANCE_VALUE_r21] = "_STORE_ATTR_INSTANCE_VALUE_r21", + [_STORE_ATTR_INSTANCE_VALUE_NULL] = "_STORE_ATTR_INSTANCE_VALUE_NULL", + [_STORE_ATTR_INSTANCE_VALUE_NULL_r01] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r01", + [_STORE_ATTR_INSTANCE_VALUE_NULL_r11] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r11", + [_STORE_ATTR_INSTANCE_VALUE_NULL_r21] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r21", + [_STORE_ATTR_INSTANCE_VALUE_NULL_r32] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r32", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", [_STORE_ATTR_SLOT_r21] = "_STORE_ATTR_SLOT_r21", + [_STORE_ATTR_SLOT_NULL] = "_STORE_ATTR_SLOT_NULL", + [_STORE_ATTR_SLOT_NULL_r01] = "_STORE_ATTR_SLOT_NULL_r01", + [_STORE_ATTR_SLOT_NULL_r11] = "_STORE_ATTR_SLOT_NULL_r11", + [_STORE_ATTR_SLOT_NULL_r21] = "_STORE_ATTR_SLOT_NULL_r21", + [_STORE_ATTR_SLOT_NULL_r32] = "_STORE_ATTR_SLOT_NULL_r32", [_STORE_ATTR_WITH_HINT] = "_STORE_ATTR_WITH_HINT", [_STORE_ATTR_WITH_HINT_r21] = "_STORE_ATTR_WITH_HINT_r21", [_STORE_DEREF] = "_STORE_DEREF", @@ -5697,10 +5735,14 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _STORE_ATTR_INSTANCE_VALUE: return 2; + case _STORE_ATTR_INSTANCE_VALUE_NULL: + return 2; case _STORE_ATTR_WITH_HINT: return 2; case _STORE_ATTR_SLOT: return 2; + case _STORE_ATTR_SLOT_NULL: + return 2; case _COMPARE_OP: return 2; case _COMPARE_OP_FLOAT: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst new file mode 100644 index 00000000000..561cda68706 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst @@ -0,0 +1 @@ +Track nullness of attributes of objects in the JIT optimizer. Patch by Hai Zhu. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4c808016a00..8bc58240e90 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2671,6 +2671,23 @@ dummy_func( Py_XDECREF(old_value); } + op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + + STAT_INC(STORE_ATTR, hit); + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; + DEOPT_IF(old_value != NULL); + FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + UNLOCK_OBJECT(owner_o); + INPUTS_DEAD(); + o = owner; + } + macro(STORE_ATTR_INSTANCE_VALUE) = unused/1 + _GUARD_TYPE_VERSION_AND_LOCK + @@ -2733,6 +2750,20 @@ dummy_func( Py_XDECREF(old_value); } + op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) { + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + + DEOPT_IF(!LOCK_OBJECT(owner_o)); + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + DEOPT_IF(old_value != NULL); + FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); + UNLOCK_OBJECT(owner_o); + INPUTS_DEAD(); + o = owner; + } + macro(STORE_ATTR_SLOT) = unused/1 + _GUARD_TYPE_VERSION + diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 8901c259525..1a705098472 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9782,6 +9782,147 @@ break; } + case _STORE_ATTR_INSTANCE_VALUE_NULL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + STAT_INC(STORE_ATTR, hit); + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE_NULL_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + value = stack_pointer[-1]; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + STAT_INC(STORE_ATTR, hit); + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE_NULL_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + value = _stack_item_0; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + STAT_INC(STORE_ATTR, hit); + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE_NULL_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + value = _stack_item_1; + uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + STAT_INC(STORE_ATTR, hit); + assert(_PyObject_GetManagedDict(owner_o) == NULL); + PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); + PyObject *old_value = *value_ptr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); + PyDictValues *values = _PyObject_InlineValues(owner_o); + Py_ssize_t index = value_ptr - values->values; + _PyDictValues_AddToInsertionOrder(values, index); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache1 = o; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _STORE_ATTR_WITH_HINT_r21: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); @@ -9914,6 +10055,157 @@ break; } + case _STORE_ATTR_SLOT_NULL_r01: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_SLOT_NULL_r11: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + owner = _stack_item_0; + value = stack_pointer[-1]; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = owner; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_SLOT_NULL_r21: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + owner = _stack_item_1; + value = _stack_item_0; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = owner; + _tos_cache0 = value; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache0 = o; + SET_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _STORE_ATTR_SLOT_NULL_r32: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef owner; + _PyStackRef value; + _PyStackRef o; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + owner = _stack_item_2; + value = _stack_item_1; + uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); + PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); + if (!LOCK_OBJECT(owner_o)) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + char *addr = (char *)owner_o + index; + STAT_INC(STORE_ATTR, hit); + PyObject *old_value = *(PyObject **)addr; + if (old_value != NULL) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = owner; + _tos_cache1 = value; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); + UNLOCK_OBJECT(owner_o); + o = owner; + _tos_cache1 = o; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _COMPARE_OP_r21: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 039aacf23ae..0a1f2672f4b 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -269,6 +269,9 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness +#define sym_new_descr_object _Py_uop_sym_new_descr_object +#define sym_get_attr _Py_uop_sym_get_attr +#define sym_set_attr _Py_uop_sym_set_attr #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing @@ -503,7 +506,6 @@ optimize_uops( int oparg = this_instr->oparg; opcode = this_instr->opcode; - if (!CURRENT_FRAME_IS_INIT_SHIM()) { stack_pointer = ctx->frame->stack_pointer; } @@ -524,9 +526,15 @@ optimize_uops( if (ctx->out_buffer.next == out_ptr) { *(ctx->out_buffer.next++) = *this_instr; } + // Track escapes - but skip when from init shim frame, since self hasn't escaped yet + bool is_init_shim = CURRENT_FRAME_IS_INIT_SHIM(); + if ((_PyUop_Flags[out_ptr->opcode] & HAS_ESCAPES_FLAG) && !is_init_shim) + { + ctx->last_escape_index = uop_buffer_length(&ctx->out_buffer) - 1; + } assert(ctx->frame != NULL); DUMP_UOP(ctx, "out", uop_buffer_length(&ctx->out_buffer) - 1, out_ptr, stack_pointer); - if (!CURRENT_FRAME_IS_INIT_SHIM() && !ctx->done) { + if (!is_init_shim && !ctx->done) { DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); ctx->frame->stack_pointer = stack_pointer; assert(STACK_LEVEL() >= 0); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 5a3480ab316..4ccecd472b3 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -38,6 +38,9 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness +#define sym_new_descr_object _Py_uop_sym_new_descr_object +#define sym_get_attr _Py_uop_sym_get_attr +#define sym_set_attr _Py_uop_sym_set_attr #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing @@ -103,6 +106,14 @@ dummy_func(void) { } op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner -- o)) { + JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value); + if (sym_is_null(old_value)) { + ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset); + } + o = owner; + } + + op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) { (void)value; o = owner; } @@ -125,7 +136,14 @@ dummy_func(void) { } op(_STORE_ATTR_SLOT, (index/1, value, owner -- o)) { - (void)index; + JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value); + if (sym_is_null(old_value)) { + ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index); + } + o = owner; + } + + op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) { (void)value; o = owner; } @@ -749,8 +767,7 @@ dummy_func(void) { } op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, o)) { - attr = sym_new_not_null(ctx); - (void)index; + attr = sym_get_attr(ctx, owner, (uint16_t)index); o = owner; } @@ -934,10 +951,14 @@ dummy_func(void) { } op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { - (void)type_version; (void)args; callable = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); + PyTypeObject *tp = _PyType_LookupByVersion(type_version); + if (tp != NULL) { + self_or_null = sym_new_descr_object(ctx, type_version); + } else { + self_or_null = sym_new_not_null(ctx); + } } op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 9dc1da3c93b..4a6f2450680 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1936,8 +1936,7 @@ JitOptRef o; owner = stack_pointer[-1]; uint16_t index = (uint16_t)this_instr->operand0; - attr = sym_new_not_null(ctx); - (void)index; + attr = sym_get_attr(ctx, owner, (uint16_t)index); o = owner; CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; @@ -2006,6 +2005,25 @@ } case _STORE_ATTR_INSTANCE_VALUE: { + JitOptRef owner; + JitOptRef value; + JitOptRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t offset = (uint16_t)this_instr->operand0; + JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value); + if (sym_is_null(old_value)) { + ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset); + } + o = owner; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + + case _STORE_ATTR_INSTANCE_VALUE_NULL: { JitOptRef owner; JitOptRef value; JitOptRef o; @@ -2044,7 +2062,25 @@ owner = stack_pointer[-1]; value = stack_pointer[-2]; uint16_t index = (uint16_t)this_instr->operand0; - (void)index; + JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value); + if (sym_is_null(old_value)) { + ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index); + } + o = owner; + CHECK_STACK_BOUNDS(-1); + stack_pointer[-2] = o; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + + case _STORE_ATTR_SLOT_NULL: { + JitOptRef owner; + JitOptRef value; + JitOptRef o; + owner = stack_pointer[-1]; + value = stack_pointer[-2]; + uint16_t index = (uint16_t)this_instr->operand0; (void)value; o = owner; CHECK_STACK_BOUNDS(-1); @@ -3192,11 +3228,15 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t type_version = (uint32_t)this_instr->operand0; - (void)type_version; (void)args; callable = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); stack_pointer[-2 - oparg] = callable; + PyTypeObject *tp = _PyType_LookupByVersion(type_version); + if (tp != NULL) { + self_or_null = sym_new_descr_object(ctx, type_version); + } else { + self_or_null = sym_new_not_null(ctx); + } stack_pointer[-1 - oparg] = self_or_null; break; } diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 51cf6e189f0..ff94807c6db 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -113,6 +113,15 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_COMPACT_INT: printf("", (void *)sym); break; + case JIT_SYM_DESCR_TAG: { + PyTypeObject *descr_type = _PyType_LookupByVersion(sym->descr.type_version); + if (descr_type) { + printf("<%s descr[%d] v%u at %p>", descr_type->tp_name, sym->descr.num_descrs, sym->descr.type_version, (void *)sym); + } else { + printf("", sym->descr.num_descrs, sym->descr.type_version, (void *)sym); + } + break; + } default: printf("", sym->tag, (void *)sym); break; @@ -320,6 +329,11 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ) sym_set_bottom(ctx, sym); } return; + case JIT_SYM_DESCR_TAG: + if (typ->tp_version_tag != sym->descr.type_version) { + sym_set_bottom(ctx, sym); + } + return; } } @@ -384,6 +398,12 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver return false; } return true; + case JIT_SYM_DESCR_TAG: + if (version != sym->descr.type_version) { + sym_set_bottom(ctx, sym); + return false; + } + return true; } Py_UNREACHABLE(); } @@ -483,6 +503,9 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val) sym_set_bottom(ctx, sym); } return; + case JIT_SYM_DESCR_TAG: + sym_set_bottom(ctx, sym); + return; } } @@ -603,7 +626,8 @@ _Py_uop_sym_get_type(JitOptRef ref) return &PyBool_Type; case JIT_SYM_COMPACT_INT: return &PyLong_Type; - + case JIT_SYM_DESCR_TAG: + return _PyType_LookupByVersion(sym->descr.type_version); } Py_UNREACHABLE(); } @@ -632,6 +656,8 @@ _Py_uop_sym_get_type_version(JitOptRef ref) return PyBool_Type.tp_version_tag; case JIT_SYM_COMPACT_INT: return PyLong_Type.tp_version_tag; + case JIT_SYM_DESCR_TAG: + return sym->descr.type_version; } Py_UNREACHABLE(); } @@ -666,6 +692,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: case JIT_SYM_COMPACT_INT: + case JIT_SYM_DESCR_TAG: return -1; case JIT_SYM_KNOWN_CLASS_TAG: /* TODO : @@ -823,6 +850,7 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_TUPLE_TAG: case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: + case JIT_SYM_DESCR_TAG: sym_set_bottom(ctx, sym); return; case JIT_SYM_BOTTOM_TAG: @@ -937,6 +965,116 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx) return PyJitRef_Wrap(sym); } +JitOptRef +_Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version) +{ + JitOptSymbol *res = sym_new(ctx); + if (res == NULL) { + return out_of_space_ref(ctx); + } + res->tag = JIT_SYM_DESCR_TAG; + res->descr.num_descrs = 0; + res->descr.descrs = NULL; + res->descr.type_version = type_version; + res->descr.last_modified_index = uop_buffer_length(&ctx->out_buffer); + return PyJitRef_Wrap(res); +} + +JitOptRef +_Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + + switch (sym->tag) { + case JIT_SYM_DESCR_TAG: + // Only return tracked slot values if: + // 1. Symbol has mappings allocated + // 2. No escape has occurred since last modification (state is fresh) + if (sym->descr.descrs != NULL && + sym->descr.last_modified_index >= ctx->last_escape_index) + { + for (int i = 0; i < sym->descr.num_descrs; i++) { + if (sym->descr.descrs[i].slot_index == slot_index) { + return PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol); + } + } + } + break; + default: + break; + } + + return _Py_uop_sym_new_not_null(ctx); +} + +static JitOptDescrMapping * +descr_arena_alloc(JitOptContext *ctx) +{ + if (ctx->d_arena.descr_curr_number + MAX_SYMBOLIC_DESCR_SIZE > ctx->d_arena.descr_max_number) { + return NULL; + } + JitOptDescrMapping *descrs = &ctx->d_arena.arena[ctx->d_arena.descr_curr_number]; + ctx->d_arena.descr_curr_number += MAX_SYMBOLIC_DESCR_SIZE; + return descrs; +} + +JitOptRef +_Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value) +{ + JitOptSymbol *sym = PyJitRef_Unwrap(ref); + int curr_index = uop_buffer_length(&ctx->out_buffer); + + switch (sym->tag) { + case JIT_SYM_DESCR_TAG: + break; + default: + return _Py_uop_sym_new_not_null(ctx); + } + + // Check escape + if (sym->descr.last_modified_index < ctx->last_escape_index) { + sym->descr.num_descrs = 0; + } + + // Get old value before updating + JitOptRef old_value = PyJitRef_NULL; + if (sym->descr.descrs != NULL) { + for (int i = 0; i < sym->descr.num_descrs; i++) { + if (sym->descr.descrs[i].slot_index == slot_index) { + old_value = PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol); + break; + } + } + } + + // Update the last modified timestamp + sym->descr.last_modified_index = curr_index; + + // Check if have arena space allocated + if (sym->descr.descrs == NULL) { + sym->descr.descrs = descr_arena_alloc(ctx); + if (sym->descr.descrs == NULL) { + return PyJitRef_IsNull(old_value) ? _Py_uop_sym_new_not_null(ctx) : old_value; + } + } + // Check if the slot already exists + for (int i = 0; i < sym->descr.num_descrs; i++) { + if (sym->descr.descrs[i].slot_index == slot_index) { + sym->descr.descrs[i].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx)); + assert(!PyJitRef_IsNull(old_value)); + return old_value; + } + } + // Add new mapping if there's space + if (sym->descr.num_descrs < MAX_SYMBOLIC_DESCR_SIZE) { + int idx = sym->descr.num_descrs++; + sym->descr.descrs[idx].slot_index = slot_index; + sym->descr.descrs[idx].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx)); + } + + return PyJitRef_IsNull(old_value) ? PyJitRef_Borrow(_Py_uop_sym_new_null(ctx)) : old_value; +} + // 0 on success, -1 on error. _Py_UOpsAbstractFrame * _Py_uop_frame_new( @@ -1026,6 +1164,10 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx) ctx->t_arena.ty_curr_number = 0; ctx->t_arena.ty_max_number = TY_ARENA_SIZE; + // Setup the arena for descriptor mappings. + ctx->d_arena.descr_curr_number = 0; + ctx->d_arena.descr_max_number = DESCR_ARENA_SIZE; + // Frame setup ctx->curr_frame_depth = 0; @@ -1036,6 +1178,7 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx) ctx->out_of_space = false; ctx->contradiction = false; ctx->builtins_watched = false; + ctx->last_escape_index = 0; } int @@ -1497,6 +1640,61 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_matches_type(ref_int, &PyLong_Type), "43 is not an int"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref_int) == val_43, "43 isn't 43"); + JitOptRef descr_obj = _Py_uop_sym_new_descr_object(ctx, 42); + TEST_PREDICATE(!_Py_uop_sym_is_null(descr_obj), "descr object is NULL"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(descr_obj), "descr object is not not-null"); + TEST_PREDICATE(_Py_uop_sym_get_type_version(descr_obj) == 42, + "descr object has wrong type version"); + + JitOptRef slot_val = _Py_uop_sym_new_const(ctx, val_42); + JitOptRef old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val); + TEST_PREDICATE(_Py_uop_sym_is_null(old_val), "set_attr on new slot should return NULL"); + JitOptRef retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, + "descr getattr(0) didn't return val_42"); + + JitOptRef missing = _Py_uop_sym_get_attr(ctx, descr_obj, 99); + TEST_PREDICATE(_Py_uop_sym_is_not_null(missing), "missing slot is not not-null"); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, missing), "missing slot is const"); + + JitOptRef slot_val2 = _Py_uop_sym_new_const(ctx, val_43); + old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val2); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, old_val) == val_42, + "set_attr should return old value (val_42)"); + retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43, + "descr getattr(0) didn't return val_43 after update"); + + // Test multiple slots + JitOptRef slot_val3 = _Py_uop_sym_new_const(ctx, val_42); + _Py_uop_sym_set_attr(ctx, descr_obj, 1, slot_val3); + retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 1); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, + "descr getattr(1) didn't return val_42"); + retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43, + "descr getattr(0) changed unexpectedly"); + + // Test escape invalidation + JitOptRef descr_obj3 = _Py_uop_sym_new_descr_object(ctx, 100); + JitOptRef escape_val = _Py_uop_sym_new_const(ctx, val_42); + _Py_uop_sym_set_attr(ctx, descr_obj3, 0, escape_val); + retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, + "descr getattr before escape didn't return val_42"); + // Simulate escape by setting last_escape_index higher + ctx->last_escape_index = INT_MAX; + retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0); + TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, retrieved), + "descr getattr after escape should not return const"); + TEST_PREDICATE(_Py_uop_sym_is_not_null(retrieved), + "descr getattr after escape should return not-null"); + ctx->last_escape_index = 0; + + JitOptRef descr_obj2 = _Py_uop_sym_new_descr_object(ctx, 42); + _Py_uop_sym_set_type_version(ctx, descr_obj2, 43); + TEST_PREDICATE(_Py_uop_sym_is_bottom(descr_obj2), + "descr object with wrong type version isn't bottom"); _Py_uop_abstractcontext_fini(ctx); Py_DECREF(val_42); Py_DECREF(val_43); From e666a01ef42939f77f4c22ca47a610df5ef8b7ab Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 30 Jan 2026 11:14:10 -0500 Subject: [PATCH 112/133] gh-144295: Fix data race in dict method lookup and global load (gh-144312) In `_PyDict_GetMethodStackRef`, only use the fast-path unicode lookup when the dict is owned by the current thread or already marked as shared. This prevents a race between the lookup and concurrent dict resizes, which may free the PyDictKeysObject (i.e., it ensures that the resize uses QSBR). Address a similar issue in `_Py_dict_lookup_threadsafe_stackref` by calling `ensure_shared_on_read()`. --- Lib/test/test_free_threading/test_dict.py | 22 ++++++++++++++ Objects/dictobject.c | 36 +++++++++++++++-------- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_free_threading/test_dict.py b/Lib/test/test_free_threading/test_dict.py index 5d5d4e226ca..1ffd924e9f4 100644 --- a/Lib/test/test_free_threading/test_dict.py +++ b/Lib/test/test_free_threading/test_dict.py @@ -245,5 +245,27 @@ def reader(): with threading_helper.start_threads([t1, t2]): pass + def test_racing_dict_update_and_method_lookup(self): + # gh-144295: test race between dict modifications and method lookups. + # Uses BytesIO because the race requires a type without Py_TPFLAGS_INLINE_VALUES + # for the _PyDict_GetMethodStackRef code path. + import io + obj = io.BytesIO() + + def writer(): + for _ in range(10000): + obj.x = 1 + del obj.x + + def reader(): + for _ in range(10000): + obj.getvalue() + + t1 = Thread(target=writer) + t2 = Thread(target=reader) + + with threading_helper.start_threads([t1, t2]): + pass + if __name__ == "__main__": unittest.main() diff --git a/Objects/dictobject.c b/Objects/dictobject.c index aea9ea84202..c1584be3f0e 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1615,7 +1615,9 @@ lookup_threadsafe_unicode(PyDictKeysObject *dk, PyObject *key, Py_hash_t hash, _ Py_ssize_t _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr) { - PyDictKeysObject *dk = _Py_atomic_load_ptr(&mp->ma_keys); + ensure_shared_on_read(mp); + + PyDictKeysObject *dk = _Py_atomic_load_ptr_acquire(&mp->ma_keys); if (dk->dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact(key)) { Py_ssize_t ix = lookup_threadsafe_unicode(dk, key, hash, value_addr); if (ix != DKIX_KEY_CHANGED) { @@ -1669,19 +1671,27 @@ _PyDict_GetMethodStackRef(PyDictObject *mp, PyObject *key, _PyStackRef *method) Py_hash_t hash = hash_unicode_key(key); #ifdef Py_GIL_DISABLED - PyDictKeysObject *dk = _Py_atomic_load_ptr_acquire(&mp->ma_keys); - if (dk->dk_kind == DICT_KEYS_UNICODE) { - _PyStackRef ref; - Py_ssize_t ix = lookup_threadsafe_unicode(dk, key, hash, &ref); - if (ix >= 0) { - assert(!PyStackRef_IsNull(ref)); - PyStackRef_XSETREF(*method, ref); - return 1; + // NOTE: We can only do the fast-path lookup if we are on the owning + // thread or if the dict is already marked as shared so that the load + // of ma_keys is safe without a lock. We cannot call ensure_shared_on_read() + // in this code path without incref'ing the dict because the dict is a + // borrowed reference protected by QSBR, and acquiring the lock could lead + // to a quiescent state (allowing the dict to be freed). + if (_Py_IsOwnedByCurrentThread((PyObject *)mp) || IS_DICT_SHARED(mp)) { + PyDictKeysObject *dk = _Py_atomic_load_ptr_acquire(&mp->ma_keys); + if (dk->dk_kind == DICT_KEYS_UNICODE) { + _PyStackRef ref; + Py_ssize_t ix = lookup_threadsafe_unicode(dk, key, hash, &ref); + if (ix >= 0) { + assert(!PyStackRef_IsNull(ref)); + PyStackRef_XSETREF(*method, ref); + return 1; + } + else if (ix == DKIX_EMPTY) { + return 0; + } + assert(ix == DKIX_KEY_CHANGED); } - else if (ix == DKIX_EMPTY) { - return 0; - } - assert(ix == DKIX_KEY_CHANGED); } #endif From a7048327ed7c6bb83c8c41d50f6d8c5470b6ad71 Mon Sep 17 00:00:00 2001 From: reiden <65756407+reidenong@users.noreply.github.com> Date: Sat, 31 Jan 2026 00:43:27 +0800 Subject: [PATCH 113/133] gh-144280: Add missing predicate symbol to case-switch (GH-144298) --- ...-01-30-15-54-50.gh-issue-144280.kgiP5R.rst | 1 + Python/optimizer_symbols.c | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-15-54-50.gh-issue-144280.kgiP5R.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-15-54-50.gh-issue-144280.kgiP5R.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-15-54-50.gh-issue-144280.kgiP5R.rst new file mode 100644 index 00000000000..d6a42031890 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-15-54-50.gh-issue-144280.kgiP5R.rst @@ -0,0 +1 @@ +Fix a bug in JIT where the predicate symbol had no truthiness diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index ff94807c6db..d79c273a099 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -113,6 +113,9 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_COMPACT_INT: printf("", (void *)sym); break; + case JIT_SYM_PREDICATE_TAG: + printf("", (void *)sym); + break; case JIT_SYM_DESCR_TAG: { PyTypeObject *descr_type = _PyType_LookupByVersion(sym->descr.type_version); if (descr_type) { @@ -692,6 +695,7 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_NON_NULL_TAG: case JIT_SYM_UNKNOWN_TAG: case JIT_SYM_COMPACT_INT: + case JIT_SYM_PREDICATE_TAG: case JIT_SYM_DESCR_TAG: return -1; case JIT_SYM_KNOWN_CLASS_TAG: @@ -1614,6 +1618,26 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) _Py_uop_sym_apply_predicate_narrowing(ctx, ref, true); TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, subject), "predicate narrowing incorrectly narrowed subject (inverted/true)"); + subject = _Py_uop_sym_new_unknown(ctx); + value = _Py_uop_sym_new_const(ctx, one_obj); + ref = _Py_uop_sym_new_predicate(ctx, subject, value, JIT_PRED_IS); + if (PyJitRef_IsNull(subject) || PyJitRef_IsNull(value) || PyJitRef_IsNull(ref)) { + goto fail; + } + TEST_PREDICATE(_Py_uop_sym_matches_type(ref, &PyBool_Type), "predicate is not boolean"); + TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, ref) == -1, "predicate is not unknown"); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, ref) == false, "predicate is constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref) == NULL, "predicate is not NULL"); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, value) == true, "value is not constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, value) == one_obj, "value is not 1"); + _Py_uop_sym_set_const(ctx, ref, Py_False); + TEST_PREDICATE(_Py_uop_sym_matches_type(ref, &PyBool_Type), "predicate is not boolean"); + TEST_PREDICATE(_Py_uop_sym_truthiness(ctx, ref) == 0, "predicate is not False"); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, ref) == true, "predicate is not constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref) == Py_False, "predicate is not False"); + TEST_PREDICATE(_Py_uop_sym_is_const(ctx, value) == true, "value is not constant"); + TEST_PREDICATE(_Py_uop_sym_get_const(ctx, value) == one_obj, "value is not 1"); + val_big = PyNumber_Lshift(_PyLong_GetOne(), PyLong_FromLong(66)); if (val_big == NULL) { goto fail; From a01694dacd8e8bbbd019e8b87dbc7bc7173cb7f1 Mon Sep 17 00:00:00 2001 From: Sam Gross Date: Fri, 30 Jan 2026 12:20:27 -0500 Subject: [PATCH 114/133] gh-120321: Make gi_yieldfrom thread-safe in free-threading build (#144292) Add a FRAME_SUSPENDED_YIELD_FROM_LOCKED state that acts as a brief lock, preventing other threads from transitioning the frame state while gen_getyieldfrom reads the yield-from object off the stack. --- Include/internal/pycore_frame.h | 9 +++-- Include/internal/pycore_lock.h | 3 ++ Lib/test/support/threading_helper.py | 23 +++++++++--- .../test_free_threading/test_generators.py | 37 +++++++++++++++++++ ...-01-27-17-49-43.gh-issue-120321.Vo7c9T.rst | 2 + Objects/genobject.c | 37 ++++++++++++++++--- Python/ceval.c | 4 +- Python/ceval_macros.h | 5 ++- Python/lock.c | 2 +- 9 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-27-17-49-43.gh-issue-120321.Vo7c9T.rst diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 8c410e9e208..50908f2cb7a 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -44,15 +44,16 @@ extern PyFrameObject* _PyFrame_New_NoTrack(PyCodeObject *code); /* other API */ typedef enum _framestate { - FRAME_CREATED = -3, - FRAME_SUSPENDED = -2, - FRAME_SUSPENDED_YIELD_FROM = -1, + FRAME_CREATED = -4, + FRAME_SUSPENDED = -3, + FRAME_SUSPENDED_YIELD_FROM = -2, + FRAME_SUSPENDED_YIELD_FROM_LOCKED = -1, FRAME_EXECUTING = 0, FRAME_COMPLETED = 1, FRAME_CLEARED = 4 } PyFrameState; -#define FRAME_STATE_SUSPENDED(S) ((S) == FRAME_SUSPENDED || (S) == FRAME_SUSPENDED_YIELD_FROM) +#define FRAME_STATE_SUSPENDED(S) ((S) >= FRAME_SUSPENDED && (S) <= FRAME_SUSPENDED_YIELD_FROM_LOCKED) #define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED) #ifdef __cplusplus diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h index c4e007e744c..e31d8b4e5c6 100644 --- a/Include/internal/pycore_lock.h +++ b/Include/internal/pycore_lock.h @@ -70,6 +70,9 @@ PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags) // error messages) otherwise returns 0. extern int _PyMutex_TryUnlock(PyMutex *m); +// Yield the processor to other threads (e.g., sched_yield). +extern void _Py_yield(void); + // PyEvent is a one-time event notification typedef struct { diff --git a/Lib/test/support/threading_helper.py b/Lib/test/support/threading_helper.py index 3e04c344a0d..cf87233f0e2 100644 --- a/Lib/test/support/threading_helper.py +++ b/Lib/test/support/threading_helper.py @@ -250,21 +250,32 @@ def requires_working_threading(*, module=False): return unittest.skipUnless(can_start_thread, msg) -def run_concurrently(worker_func, nthreads, args=(), kwargs={}): +def run_concurrently(worker_func, nthreads=None, args=(), kwargs={}): """ - Run the worker function concurrently in multiple threads. + Run the worker function(s) concurrently in multiple threads. + + If `worker_func` is a single callable, it is used for all threads. + If it is a list of callables, each callable is used for one thread. """ + from collections.abc import Iterable + + if nthreads is None: + nthreads = len(worker_func) + if not isinstance(worker_func, Iterable): + worker_func = [worker_func] * nthreads + assert len(worker_func) == nthreads + barrier = threading.Barrier(nthreads) - def wrapper_func(*args, **kwargs): + def wrapper_func(func, *args, **kwargs): # Wait for all threads to reach this point before proceeding. barrier.wait() - worker_func(*args, **kwargs) + func(*args, **kwargs) with catch_threading_exception() as cm: workers = [ - threading.Thread(target=wrapper_func, args=args, kwargs=kwargs) - for _ in range(nthreads) + threading.Thread(target=wrapper_func, args=(func, *args), kwargs=kwargs) + for func in worker_func ] with start_threads(workers): pass diff --git a/Lib/test/test_free_threading/test_generators.py b/Lib/test/test_free_threading/test_generators.py index 11f59301bcd..2b41e28896f 100644 --- a/Lib/test/test_free_threading/test_generators.py +++ b/Lib/test/test_free_threading/test_generators.py @@ -1,4 +1,6 @@ import concurrent.futures +import itertools +import threading import unittest from threading import Barrier from unittest import TestCase @@ -120,3 +122,38 @@ def drive_generator(g): g = gen() threading_helper.run_concurrently(drive_generator, self.NUM_THREADS, args=(g,)) + + def test_concurrent_gi_yieldfrom(self): + def gen_yield_from(): + yield from itertools.count() + + g = gen_yield_from() + next(g) # Put in FRAME_SUSPENDED_YIELD_FROM state + + def read_yieldfrom(gen): + for _ in range(10000): + self.assertIsNotNone(gen.gi_yieldfrom) + + threading_helper.run_concurrently(read_yieldfrom, self.NUM_THREADS, args=(g,)) + + def test_gi_yieldfrom_close_race(self): + def gen_yield_from(): + yield from itertools.count() + + g = gen_yield_from() + next(g) + + done = threading.Event() + + def reader(): + while not done.is_set(): + g.gi_yieldfrom + + def closer(): + try: + g.close() + except ValueError: + pass + done.set() + + threading_helper.run_concurrently([reader, closer]) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-27-17-49-43.gh-issue-120321.Vo7c9T.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-27-17-49-43.gh-issue-120321.Vo7c9T.rst new file mode 100644 index 00000000000..052ed07c123 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-27-17-49-43.gh-issue-120321.Vo7c9T.rst @@ -0,0 +1,2 @@ +Made ``gi_yieldfrom`` thread-safe in the free-threading build +by using a lightweight lock on the frame state. diff --git a/Objects/genobject.c b/Objects/genobject.c index fcdb9017a35..5ff4618255c 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -10,6 +10,7 @@ #include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED() #include "pycore_genobject.h" // _PyGen_SetStopIterationValue() #include "pycore_interpframe.h" // _PyFrame_GetCode() +#include "pycore_lock.h" // _Py_yield() #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_opcode_utils.h" // RESUME_AFTER_YIELD_FROM @@ -37,8 +38,20 @@ static PyObject* async_gen_athrow_new(PyAsyncGenObject *, PyObject *); _Py_CAST(PyAsyncGenObject*, (op)) #ifdef Py_GIL_DISABLED +static bool +gen_try_set_frame_state(PyGenObject *gen, int8_t *expected, int8_t state) +{ + if (*expected == FRAME_SUSPENDED_YIELD_FROM_LOCKED) { + // Wait for the in-progress gi_yieldfrom read to complete + _Py_yield(); + *expected = _Py_atomic_load_int8_relaxed(&gen->gi_frame_state); + return false; + } + return _Py_atomic_compare_exchange_int8(&gen->gi_frame_state, expected, state); +} + # define _Py_GEN_TRY_SET_FRAME_STATE(gen, expected, state) \ - _Py_atomic_compare_exchange_int8(&(gen)->gi_frame_state, &expected, (state)) + gen_try_set_frame_state((gen), &(expected), (state)) #else # define _Py_GEN_TRY_SET_FRAME_STATE(gen, expected, state) \ ((gen)->gi_frame_state = (state), true) @@ -470,9 +483,7 @@ gen_close(PyObject *self, PyObject *args) return NULL; } - assert(frame_state == FRAME_SUSPENDED_YIELD_FROM || - frame_state == FRAME_SUSPENDED); - + assert(FRAME_STATE_SUSPENDED(frame_state)); } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_EXECUTING)); int err = 0; @@ -876,12 +887,26 @@ static PyObject * gen_getyieldfrom(PyObject *self, void *Py_UNUSED(ignored)) { PyGenObject *gen = _PyGen_CAST(self); - int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(gen->gi_frame_state); +#ifdef Py_GIL_DISABLED + int8_t frame_state = _Py_atomic_load_int8_relaxed(&gen->gi_frame_state); + do { + if (frame_state != FRAME_SUSPENDED_YIELD_FROM && + frame_state != FRAME_SUSPENDED_YIELD_FROM_LOCKED) + { + Py_RETURN_NONE; + } + } while (!_Py_GEN_TRY_SET_FRAME_STATE(gen, frame_state, FRAME_SUSPENDED_YIELD_FROM_LOCKED)); + + PyObject *result = PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(&gen->gi_iframe)); + _Py_atomic_store_int8_release(&gen->gi_frame_state, FRAME_SUSPENDED_YIELD_FROM); + return result; +#else + int8_t frame_state = gen->gi_frame_state; if (frame_state != FRAME_SUSPENDED_YIELD_FROM) { Py_RETURN_NONE; } - // TODO: still not thread-safe with free threading return PyStackRef_AsPyObjectNew(_PyFrame_StackPeek(&gen->gi_iframe)); +#endif } diff --git a/Python/ceval.c b/Python/ceval.c index 04ae7b4d86f..c59f20bbf1e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3391,7 +3391,9 @@ _PyEval_GetAwaitable(PyObject *iterable, int oparg) else if (PyCoro_CheckExact(iter)) { PyCoroObject *coro = (PyCoroObject *)iter; int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED(coro->cr_frame_state); - if (frame_state == FRAME_SUSPENDED_YIELD_FROM) { + if (frame_state == FRAME_SUSPENDED_YIELD_FROM || + frame_state == FRAME_SUSPENDED_YIELD_FROM_LOCKED) + { /* `iter` is a coroutine object that is being awaited. */ Py_CLEAR(iter); _PyErr_SetString(PyThreadState_GET(), PyExc_RuntimeError, diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index 1cbeb18d02c..b127812b4bf 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -522,19 +522,22 @@ 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) { + while (frame_state < FRAME_SUSPENDED_YIELD_FROM_LOCKED) { if (_Py_atomic_compare_exchange_int8(&gen->gi_frame_state, &frame_state, FRAME_EXECUTING)) { return true; } } + // NB: We return false for FRAME_SUSPENDED_YIELD_FROM_LOCKED as well. + // That case is rare enough that we can just handle it in the deopt. return false; } #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) { + assert(gen->gi_frame_state != FRAME_SUSPENDED_YIELD_FROM_LOCKED); gen->gi_frame_state = FRAME_EXECUTING; return true; } diff --git a/Python/lock.c b/Python/lock.c index 12b5ebc89ae..ad97bfd93c8 100644 --- a/Python/lock.c +++ b/Python/lock.c @@ -40,7 +40,7 @@ struct mutex_entry { int handed_off; }; -static void +void _Py_yield(void) { #ifdef MS_WINDOWS From 96e4cd698a3000382f1796366e9c963902381382 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Fri, 30 Jan 2026 18:18:56 +0000 Subject: [PATCH 115/133] gh-144319: Fix huge page safety in pymalloc arenas (#144331) The pymalloc huge page support had two problems. First, on architectures where the default huge page size exceeds the arena size (e.g. 32 MiB on PPC, 512 MiB on ARM64 with 64 KB base pages), mmap with MAP_HUGETLB silently allocates a full huge page even when the requested size is smaller. The subsequent munmap with the original arena size then fails with EINVAL, permanently leaking the entire huge page. Second, huge pages were always attempted when compiled in, with no way to disable them at runtime. On Linux, if the huge page pool is exhausted, page faults including copy-on-write faults after fork deliver SIGBUS and kill the process. The arena allocator now queries the system huge page size from /proc/meminfo and skips MAP_HUGETLB when the arena size is not a multiple of it. Huge pages also now require explicit opt-in at runtime via the PYTHON_PYMALLOC_HUGEPAGES environment variable, which is read through PyConfig and respects -E and -I flags. The config field pymalloc_hugepages is propagated to the runtime allocators struct so the low-level arena allocator can check it without calling getenv directly. --- Doc/using/cmdline.rst | 21 +++++++ Doc/using/configure.rst | 6 ++ Doc/whatsnew/3.15.rst | 2 + Include/cpython/initconfig.h | 1 + Include/internal/pycore_runtime_structs.h | 1 + Lib/test/test_capi/test_config.py | 1 + Lib/test/test_embed.py | 4 ++ Objects/obmalloc.c | 75 +++++++++++++++++++---- Programs/_testembed.c | 2 + Python/initconfig.c | 18 ++++++ 10 files changed, 120 insertions(+), 11 deletions(-) diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst index aff165191b7..c97058119ae 100644 --- a/Doc/using/cmdline.rst +++ b/Doc/using/cmdline.rst @@ -1087,6 +1087,27 @@ conflict. It now has no effect if set to an empty string. +.. envvar:: PYTHON_PYMALLOC_HUGEPAGES + + If set to a non-zero integer, enable huge page support for + :ref:`pymalloc ` arenas. Set to ``0`` or unset to disable. + Python must be compiled with :option:`--with-pymalloc-hugepages` for this + variable to have any effect. + + When enabled, arena allocation uses ``MAP_HUGETLB`` (Linux) or + ``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages if + huge pages are not available. + + .. warning:: + + On Linux, if the huge-page pool is exhausted, page faults — including + copy-on-write faults triggered by :func:`os.fork` — deliver ``SIGBUS`` + and kill the process. Only enable this in environments where the + huge-page pool is properly sized and fork-safety is not a concern. + + .. versionadded:: next + + .. envvar:: PYTHONLEGACYWINDOWSFSENCODING If set to a non-empty string, the default :term:`filesystem encoding and diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index c455272af72..26322045879 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -790,6 +790,12 @@ also be used to improve performance. 2 MiB and arena allocation uses ``MAP_HUGETLB`` (Linux) or ``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages. + Even when compiled with this option, huge pages are **not** used at runtime + unless the :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable is set + to ``1``. This opt-in is required because huge pages carry risks on Linux: + if the huge-page pool is exhausted, page faults (including copy-on-write + faults after :func:`os.fork`) deliver ``SIGBUS`` and kill the process. + The configure script checks that the platform supports ``MAP_HUGETLB`` and emits a warning if it is not available. diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 68c491f8a8c..637dd0cca24 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -1482,6 +1482,8 @@ Build changes increases to 2 MiB and allocation uses ``MAP_HUGETLB`` (Linux) or ``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages. On Windows, use ``build.bat --pymalloc-hugepages``. + At runtime, huge pages must be explicitly enabled by setting the + :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable to ``1``. * Annotating anonymous mmap usage is now supported if Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME ` (Linux 5.17 or newer). diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h index 1c979d91a40..5606ebeb7c9 100644 --- a/Include/cpython/initconfig.h +++ b/Include/cpython/initconfig.h @@ -149,6 +149,7 @@ typedef struct PyConfig { int dump_refs; wchar_t *dump_refs_file; int malloc_stats; + int pymalloc_hugepages; wchar_t *filesystem_encoding; wchar_t *filesystem_errors; wchar_t *pycache_prefix; diff --git a/Include/internal/pycore_runtime_structs.h b/Include/internal/pycore_runtime_structs.h index 92387031ad7..f48d203dda0 100644 --- a/Include/internal/pycore_runtime_structs.h +++ b/Include/internal/pycore_runtime_structs.h @@ -31,6 +31,7 @@ struct _pymem_allocators { debug_alloc_api_t obj; } debug; int is_debug_enabled; + int use_hugepages; PyObjectArenaAllocator obj_arena; }; diff --git a/Lib/test/test_capi/test_config.py b/Lib/test/test_capi/test_config.py index 04a27de8d84..b04d0923926 100644 --- a/Lib/test/test_capi/test_config.py +++ b/Lib/test/test_capi/test_config.py @@ -63,6 +63,7 @@ def test_config_get(self): ("interactive", bool, None), ("isolated", bool, None), ("malloc_stats", bool, None), + ("pymalloc_hugepages", bool, None), ("module_search_paths", list[str], "path"), ("optimization_level", int, None), ("orig_argv", list[str], "orig_argv"), diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index b5367941227..29b1249b10d 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -642,6 +642,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): 'dump_refs': False, 'dump_refs_file': None, 'malloc_stats': False, + 'pymalloc_hugepages': False, 'filesystem_encoding': GET_DEFAULT_CONFIG, 'filesystem_errors': GET_DEFAULT_CONFIG, @@ -1044,6 +1045,7 @@ def test_init_from_config(self): 'code_debug_ranges': False, 'show_ref_count': True, 'malloc_stats': True, + 'pymalloc_hugepages': True, 'stdio_encoding': 'iso8859-1', 'stdio_errors': 'replace', @@ -1109,6 +1111,7 @@ def test_init_compat_env(self): 'import_time': 1, 'code_debug_ranges': False, 'malloc_stats': True, + 'pymalloc_hugepages': True, 'inspect': True, 'optimization_level': 2, 'pythonpath_env': '/my/path', @@ -1145,6 +1148,7 @@ def test_init_python_env(self): 'import_time': 1, 'code_debug_ranges': False, 'malloc_stats': True, + 'pymalloc_hugepages': True, 'inspect': True, 'optimization_level': 2, 'pythonpath_env': '/my/path', diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 71dc4bf0d04..ce2e39790bd 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -13,6 +13,7 @@ #include // malloc() #include +#include // fopen(), fgets(), sscanf() #ifdef WITH_MIMALLOC // Forward declarations of functions used in our mimalloc modifications static void _PyMem_mi_page_clear_qsbr(mi_page_t *page); @@ -492,16 +493,57 @@ _PyMem_DefaultRawWcsdup(const wchar_t *str) # endif #endif +/* Return the system's default huge page size in bytes, or 0 if it + * cannot be determined. The result is cached after the first call. + * + * This is Linux-only (/proc/meminfo). On other systems that define + * MAP_HUGETLB the caller should skip huge pages gracefully. */ +#if defined(PYMALLOC_USE_HUGEPAGES) && defined(ARENAS_USE_MMAP) && defined(MAP_HUGETLB) +static size_t +_pymalloc_system_hugepage_size(void) +{ + static size_t hp_size = 0; + static int initialized = 0; + + if (initialized) { + return hp_size; + } + +#ifdef __linux__ + FILE *f = fopen("/proc/meminfo", "r"); + if (f != NULL) { + char line[256]; + while (fgets(line, sizeof(line), f)) { + unsigned long size_kb; + if (sscanf(line, "Hugepagesize: %lu kB", &size_kb) == 1) { + hp_size = (size_t)size_kb * 1024; + break; + } + } + fclose(f); + } +#endif + + initialized = 1; + return hp_size; +} +#endif + void * _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size) { #ifdef MS_WINDOWS # ifdef PYMALLOC_USE_HUGEPAGES - void *ptr = VirtualAlloc(NULL, size, - MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, - PAGE_READWRITE); - if (ptr != NULL) - return ptr; + if (_PyRuntime.allocators.use_hugepages) { + SIZE_T lp_size = GetLargePageMinimum(); + if (lp_size > 0 && size % lp_size == 0) { + void *ptr = VirtualAlloc(NULL, size, + MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, + PAGE_READWRITE); + if (ptr != NULL) + return ptr; + } + } /* Fall back to regular pages */ # endif return VirtualAlloc(NULL, size, @@ -510,12 +552,23 @@ _PyMem_ArenaAlloc(void *Py_UNUSED(ctx), size_t size) void *ptr; # ifdef PYMALLOC_USE_HUGEPAGES # ifdef MAP_HUGETLB - ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); - if (ptr != MAP_FAILED) { - assert(ptr != NULL); - (void)_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc:hugepage"); - return ptr; + if (_PyRuntime.allocators.use_hugepages) { + size_t hp_size = _pymalloc_system_hugepage_size(); + /* Only use huge pages if the arena size is a multiple of the + * system's default huge page size. When the arena is smaller + * than the huge page, mmap still succeeds but silently + * allocates an entire huge page; the subsequent munmap with + * the smaller arena size then fails with EINVAL, leaking + * all of that memory. */ + if (hp_size > 0 && size % hp_size == 0) { + ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0); + if (ptr != MAP_FAILED) { + assert(ptr != NULL); + (void)_PyAnnotateMemoryMap(ptr, size, "cpython:pymalloc:hugepage"); + return ptr; + } + } } /* Fall back to regular pages */ # endif diff --git a/Programs/_testembed.c b/Programs/_testembed.c index c5e764e426b..38f546b976c 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -639,6 +639,7 @@ static int test_init_from_config(void) putenv("PYTHONMALLOCSTATS=0"); config.malloc_stats = 1; + config.pymalloc_hugepages = 1; putenv("PYTHONPYCACHEPREFIX=env_pycache_prefix"); config_set_string(&config, &config.pycache_prefix, L"conf_pycache_prefix"); @@ -795,6 +796,7 @@ static void set_most_env_vars(void) putenv("PYTHONPROFILEIMPORTTIME=1"); putenv("PYTHONNODEBUGRANGES=1"); putenv("PYTHONMALLOCSTATS=1"); + putenv("PYTHON_PYMALLOC_HUGEPAGES=1"); putenv("PYTHONUTF8=1"); putenv("PYTHONVERBOSE=1"); putenv("PYTHONINSPECT=1"); diff --git a/Python/initconfig.c b/Python/initconfig.c index 9cdc10c4e78..46fd8929041 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -160,6 +160,7 @@ static const PyConfigSpec PYCONFIG_SPEC[] = { SPEC(legacy_windows_stdio, BOOL, READ_ONLY, NO_SYS), #endif SPEC(malloc_stats, BOOL, READ_ONLY, NO_SYS), + SPEC(pymalloc_hugepages, BOOL, READ_ONLY, NO_SYS), SPEC(orig_argv, WSTR_LIST, READ_ONLY, SYS_ATTR("orig_argv")), SPEC(parse_argv, BOOL, READ_ONLY, NO_SYS), SPEC(pathconfig_warnings, BOOL, READ_ONLY, NO_SYS), @@ -900,6 +901,7 @@ config_check_consistency(const PyConfig *config) assert(config->show_ref_count >= 0); assert(config->dump_refs >= 0); assert(config->malloc_stats >= 0); + assert(config->pymalloc_hugepages >= 0); assert(config->site_import >= 0); assert(config->bytes_warning >= 0); assert(config->warn_default_encoding >= 0); @@ -1879,6 +1881,18 @@ config_read_env_vars(PyConfig *config) if (config_get_env(config, "PYTHONMALLOCSTATS")) { config->malloc_stats = 1; } + { + const char *env = _Py_GetEnv(use_env, "PYTHON_PYMALLOC_HUGEPAGES"); + if (env) { + int value; + if (_Py_str_to_int(env, &value) < 0 || value < 0) { + /* PYTHON_PYMALLOC_HUGEPAGES=text or negative + behaves as PYTHON_PYMALLOC_HUGEPAGES=1 */ + value = 1; + } + config->pymalloc_hugepages = (value > 0); + } + } if (config->dump_refs_file == NULL) { status = CONFIG_GET_ENV_DUP(config, &config->dump_refs_file, @@ -2812,6 +2826,10 @@ _PyConfig_Write(const PyConfig *config, _PyRuntimeState *runtime) return _PyStatus_NO_MEMORY(); } +#ifdef PYMALLOC_USE_HUGEPAGES + runtime->allocators.use_hugepages = config->pymalloc_hugepages; +#endif + return _PyStatus_OK(); } From ccbe41e27cdb441033189f06148c23528275214b Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Fri, 30 Jan 2026 23:37:52 -0500 Subject: [PATCH 116/133] gh-143055: Implementation of PEP 798 (#143056) Co-authored-by: Jelle Zijlstra --- Doc/reference/expressions.rst | 42 +- Doc/tutorial/classes.rst | 19 + Doc/tutorial/datastructures.rst | 64 +- Doc/whatsnew/3.15.rst | 41 + Grammar/python.gram | 66 +- Lib/test/test_exceptions.py | 4 +- Lib/test/test_unpack_ex.py | 212 +- ...-12-21-18-12-30.gh-issue-143055.PzwccL.rst | 1 + Parser/Python.asdl | 2 +- Parser/parser.c | 6358 +++++++++-------- Python/Python-ast.c | 24 +- Python/ast.c | 6 +- Python/ast_preprocess.c | 4 +- Python/codegen.c | 134 +- 14 files changed, 4069 insertions(+), 2908 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-21-18-12-30.gh-issue-143055.PzwccL.rst diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 165dfa69f88..32f2d4596fe 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -266,17 +266,19 @@ called "displays", each of them in two flavors: Common syntax elements for comprehensions are: .. productionlist:: python-grammar - comprehension: `assignment_expression` `comp_for` + comprehension: `flexible_expression` `comp_for` comp_for: ["async"] "for" `target_list` "in" `or_test` [`comp_iter`] comp_iter: `comp_for` | `comp_if` comp_if: "if" `or_test` [`comp_iter`] The comprehension consists of a single expression followed by at least one -:keyword:`!for` clause and zero or more :keyword:`!for` or :keyword:`!if` clauses. -In this case, the elements of the new container are those that would be produced -by considering each of the :keyword:`!for` or :keyword:`!if` clauses a block, -nesting from left to right, and evaluating the expression to produce an element -each time the innermost block is reached. +:keyword:`!for` clause and zero or more :keyword:`!for` or :keyword:`!if` +clauses. In this case, the elements of the new container are those that would +be produced by considering each of the :keyword:`!for` or :keyword:`!if` +clauses a block, nesting from left to right, and evaluating the expression to +produce an element each time the innermost block is reached. If the expression +is starred, the result will instead be unpacked to produce zero or more +elements. However, aside from the iterable expression in the leftmost :keyword:`!for` clause, the comprehension is executed in a separate implicitly nested scope. This ensures @@ -321,6 +323,9 @@ See also :pep:`530`. asynchronous functions. Outer comprehensions implicitly become asynchronous. +.. versionchanged:: next + Unpacking with the ``*`` operator is now allowed in the expression. + .. _lists: @@ -396,8 +401,8 @@ enclosed in curly braces: .. productionlist:: python-grammar dict_display: "{" [`dict_item_list` | `dict_comprehension`] "}" dict_item_list: `dict_item` ("," `dict_item`)* [","] + dict_comprehension: `dict_item` `comp_for` dict_item: `expression` ":" `expression` | "**" `or_expr` - dict_comprehension: `expression` ":" `expression` `comp_for` A dictionary display yields a new dictionary object. @@ -419,10 +424,21 @@ earlier dict items and earlier dictionary unpackings. .. versionadded:: 3.5 Unpacking into dictionary displays, originally proposed by :pep:`448`. -A dict comprehension, in contrast to list and set comprehensions, needs two -expressions separated with a colon followed by the usual "for" and "if" clauses. -When the comprehension is run, the resulting key and value elements are inserted -in the new dictionary in the order they are produced. +A dict comprehension may take one of two forms: + +- The first form uses two expressions separated with a colon followed by the + usual "for" and "if" clauses. When the comprehension is run, the resulting + key and value elements are inserted in the new dictionary in the order they + are produced. + +- The second form uses a single expression prefixed by the ``**`` dictionary + unpacking operator followed by the usual "for" and "if" clauses. When the + comprehension is evaluated, the expression is evaluated and then unpacked, + inserting zero or more key/value pairs into the new dictionary. + +Both forms of dictionary comprehension retain the property that if the same key +is specified multiple times, the associated value in the resulting dictionary +will be the last one specified. .. index:: pair: immutable; object hashable @@ -439,6 +455,8 @@ prevails. the key. Starting with 3.8, the key is evaluated before the value, as proposed by :pep:`572`. +.. versionchanged:: next + Unpacking with the ``**`` operator is now allowed in dictionary comprehensions. .. _genexpr: @@ -453,7 +471,7 @@ Generator expressions A generator expression is a compact generator notation in parentheses: .. productionlist:: python-grammar - generator_expression: "(" `expression` `comp_for` ")" + generator_expression: "(" `flexible_expression` `comp_for` ")" A generator expression yields a new generator object. Its syntax is the same as for comprehensions, except that it is enclosed in parentheses instead of diff --git a/Doc/tutorial/classes.rst b/Doc/tutorial/classes.rst index 9ab003d5cd3..7ab0b427a6c 100644 --- a/Doc/tutorial/classes.rst +++ b/Doc/tutorial/classes.rst @@ -929,6 +929,25 @@ Examples:: >>> list(data[i] for i in range(len(data)-1, -1, -1)) ['f', 'l', 'o', 'g'] + >>> x = [[1,2,3], [], [4, 5]] + >>> g = (*i for i in x) + >>> list(g) + [1, 2, 3, 4, 5] + +In most cases, generator expressions must be wrapped in parentheses. As a +special case, however, when provided as the sole argument to a function (as in +the examples involving ``sum``, ``set``, ``max``, and ``list`` above), the +generator expression does not need to be wrapped in an additional set of +parentheses. That is to say, the following two pieces of code are semantically +equivalent:: + + >>> f(x for x in y) + >>> f((x for x in y)) + +as are the following:: + + >>> f(*x for x in y) + >>> f((*x for x in y)) .. rubric:: Footnotes diff --git a/Doc/tutorial/datastructures.rst b/Doc/tutorial/datastructures.rst index 7e02e74177c..ccad53a5b2d 100644 --- a/Doc/tutorial/datastructures.rst +++ b/Doc/tutorial/datastructures.rst @@ -333,6 +333,47 @@ The :func:`zip` function would do a great job for this use case:: See :ref:`tut-unpacking-arguments` for details on the asterisk in this line. +Unpacking in Lists and List Comprehensions +------------------------------------------ + +The section on :ref:`tut-unpacking-arguments` describes the use of ``*`` to +"unpack" the elements of an iterable object, providing each one seperately as +an argument to a function. Unpacking can also be used in other contexts, for +example, when creating lists. When specifying elements of a list, prefixing an +expression by a ``*`` will unpack the result of that expression, adding each of +its elements to the list we're creating:: + + >>> x = [1, 2, 3] + >>> [0, *x, 4, 5, 6] + [0, 1, 2, 3, 4, 5, 6] + +This only works if the expression following the ``*`` evaluates to an iterable +object; trying to unpack a non-iterable object will raise an exception:: + + >>> x = 1 + >>> [0, *x, 2, 3, 4] + Traceback (most recent call last): + File "", line 1, in + [0, *x, 2, 3, 4] + TypeError: Value after * must be an iterable, not int + +Unpacking can also be used in list comprehensions, as a way to build a new list +representing the concatenation of an arbitrary number of iterables:: + + >>> x = [[1, 2, 3], [4, 5, 6], [], [7], [8, 9]] + >>> [*element for element in x] + [1, 2, 3, 4, 5, 6, 7, 8, 9] + +Note that the effect is that each element from ``x`` is unpacked. This works +for arbitrary iterable objects, not just lists:: + + >>> x = [[1, 2, 3], 'cat', {'spam': 'eggs'}] + >>> [*element for element in x] + [1, 2, 3, 'c', 'a', 't', 'spam'] + +But if the objects in ``x`` are not iterable, this expression would again raise +an exception. + .. _tut-del: The :keyword:`!del` statement @@ -394,7 +435,10 @@ A tuple consists of a number of values separated by commas, for instance:: >>> v = ([1, 2, 3], [3, 2, 1]) >>> v ([1, 2, 3], [3, 2, 1]) - + >>> # they support unpacking just like lists: + >>> x = [1, 2, 3] + >>> 0, *x, 4 + (0, 1, 2, 3, 4) As you see, on output tuples are always enclosed in parentheses, so that nested tuples are interpreted correctly; they may be input with or without surrounding @@ -480,12 +524,16 @@ Here is a brief demonstration:: {'r', 'd', 'b', 'm', 'z', 'l'} Similarly to :ref:`list comprehensions `, set comprehensions -are also supported:: +are also supported, including comprehensions with unpacking:: >>> a = {x for x in 'abracadabra' if x not in 'abc'} >>> a {'r', 'd'} + >>> fruits = [{'apple', 'avocado', 'apricot'}, {'banana', 'blueberry'}] + >>> {*fruit for fruit in fruits} + {'blueberry', 'banana', 'avocado', 'apple', 'apricot'} + .. _tut-dictionaries: @@ -563,6 +611,18 @@ arbitrary key and value expressions:: >>> {x: x**2 for x in (2, 4, 6)} {2: 4, 4: 16, 6: 36} +And dictionary unpacking (via ``**``) can be used to merge multiple +dictionaries:: + + >>> odds = {i: i**2 for i in (1, 3, 5)} + >>> evens = {i: i**2 for i in (2, 4, 6)} + >>> {**odds, **evens} + {1: 1, 3: 9, 5: 25, 2: 4, 4: 16, 6: 36} + + >>> all_values = [odds, evens, {0: 0}] + >>> {**i for i in all_values} + {1: 1, 3: 9, 5: 25, 2: 4, 4: 16, 6: 36, 0: 0} + When the keys are simple strings, it is sometimes easier to specify pairs using keyword arguments:: diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 637dd0cca24..b9178fb794a 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -69,6 +69,8 @@ Summary -- Release highlights profiling tools ` * :pep:`799`: :ref:`Tachyon: High frequency statistical sampling profiler profiling tools ` +* :pep:`798`: :ref:`Unpacking in Comprehensions + ` * :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding ` * :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object @@ -187,6 +189,45 @@ available output formats, profiling modes, and configuration options. (Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953` and :gh:`138122`.) +.. _whatsnew315-unpacking-in-comprehensions: + +:pep:`798`: Unpacking in Comprehensions +--------------------------------------- + +List, set, and dictionary comprehensions, as well as generator expressions, now +support unpacking with ``*`` and ``**``. This extends the unpacking syntax +from :pep:`448` to comprehensions, providing a new syntax for combining an +arbitrary number of iterables or dictionaries into a single flat structure. +This new syntax is a direct alternative to nested comprehensions, +:func:`itertools.chain`, and :meth:`itertools.chain.from_iterable`. For +example:: + + >>> lists = [[1, 2], [3, 4], [5]] + >>> [*L for L in lists] # equivalent to [x for L in lists for x in L] + [1, 2, 3, 4, 5] + + >>> sets = [{1, 2}, {2, 3}, {3, 4}] + >>> {*s for s in sets} # equivalent to {x for s in sets for x in s} + {1, 2, 3, 4} + + >>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}] + >>> {**d for d in dicts} # equivalent to {k: v for d in dicts for k,v in d.items()} + {'a': 3, 'b': 2} + +Generator expressions can similarly use unpacking to yield values from multiple +iterables:: + + >>> gen = (*L for L in lists) # equivalent to (x for L in lists for x in L) + >>> list(gen) + [1, 2, 3, 4, 5] + +This change also extends to asynchronous generator expressions, such that, for +example, ``(*a async for a in agen())`` is equivalent to ``(x async for a in +agen() for x in a)``. + +.. seealso:: :pep:`798` for further details. + +(Contributed by Adam Hartz in :gh:`143055`.) .. _whatsnew315-improved-error-messages: diff --git a/Grammar/python.gram b/Grammar/python.gram index 110136af81b..9698d6e2010 100644 --- a/Grammar/python.gram +++ b/Grammar/python.gram @@ -709,12 +709,16 @@ expressions[expr_ty]: | expression expression[expr_ty] (memo): + | invalid_if_expression | invalid_expression | invalid_legacy_expression - | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) } + | if_expression | disjunction | lambdef +if_expression[expr_ty]: + | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) } + yield_expr[expr_ty]: | 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) } | 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) } @@ -731,10 +735,16 @@ star_expression[expr_ty] (memo): star_named_expressions[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression+ [','] { a } +star_named_expressions_sequence[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression_sequence+ [','] { a } + star_named_expression[expr_ty]: | '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) } | named_expression +star_named_expression_sequence[expr_ty]: + | invalid_starred_expression_unpacking_sequence + | star_named_expression + assignment_expression[expr_ty]: | a=NAME ':=' ~ b=expression { CHECK_VERSION(expr_ty, 8, "Assignment expressions are", @@ -882,9 +892,9 @@ atom[expr_ty]: | 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) } | &(STRING|FSTRING_START|TSTRING_START) strings | NUMBER - | &'(' (tuple | group | genexp) - | &'[' (list | listcomp) - | &'{' (dict | set | dictcomp | setcomp) + | &'(' (genexp | tuple | group) + | &'[' (listcomp | list) + | &'{' (dictcomp | setcomp | dict | set) | '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) } group[expr_ty]: @@ -998,13 +1008,13 @@ strings[expr_ty] (memo): | a[asdl_expr_seq*]=tstring+ { _PyPegen_concatenate_tstrings(p, a, EXTRA) } list[expr_ty]: - | '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) } + | '[' a=[star_named_expressions_sequence] ']' { _PyAST_List(a, Load, EXTRA) } tuple[expr_ty]: - | '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' { + | '(' a=[y=star_named_expression_sequence ',' z=[star_named_expressions_sequence] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' { _PyAST_Tuple(a, Load, EXTRA) } -set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) } +set[expr_ty]: '{' a=star_named_expressions_sequence '}' { _PyAST_Set(a, EXTRA) } # Dicts # ----- @@ -1040,20 +1050,20 @@ for_if_clause[comprehension_ty]: | invalid_for_target listcomp[expr_ty]: - | '[' a=named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) } + | '[' a=star_named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) } | invalid_comprehension setcomp[expr_ty]: - | '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) } + | '{' a=star_named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) } | invalid_comprehension genexp[expr_ty]: - | '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) } + | '(' a=( assignment_expression | expression !':=' | starred_expression ) b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) } | invalid_comprehension dictcomp[expr_ty]: | '{' a=kvpair b=for_if_clauses '}' { _PyAST_DictComp(a->key, a->value, b, EXTRA) } - | invalid_dict_comprehension + | '{' '**' a=expression b=for_if_clauses '}' { _PyAST_DictComp(a, NULL, b, EXTRA) } # FUNCTION CALL ARGUMENTS # ======================= @@ -1262,6 +1272,12 @@ invalid_expression: | a='lambda' [lambda_params] b=':' &TSTRING_MIDDLE { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "t-string: lambda expressions are not allowed without parentheses") } +invalid_if_expression: + | disjunction 'if' b=disjunction 'else' a='*' { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot unpack only part of a conditional expression") } + | disjunction 'if' b=disjunction 'else' a='**' { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use dict unpacking on only part of a conditional expression") } + invalid_named_expression(memo): | a=expression ':=' expression { RAISE_SYNTAX_ERROR_KNOWN_LOCATION( @@ -1326,16 +1342,15 @@ invalid_assert_stmt: invalid_block: | NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") } invalid_comprehension: - | ('[' | '(' | '{') a=starred_expression for_if_clauses { - RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable unpacking cannot be used in comprehension") } + | '[' a='**' b=expression for_if_clauses { + RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in list comprehension") } + | '(' a='**' b=expression for_if_clauses { + RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in generator expression") } | ('[' | '{') a=star_named_expression ',' b=star_named_expressions for_if_clauses { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, expr_ty), "did you forget parentheses around the comprehension target?") } | ('[' | '{') a=star_named_expression b=',' for_if_clauses { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "did you forget parentheses around the comprehension target?") } -invalid_dict_comprehension: - | '{' a='**' bitwise_or for_if_clauses '}' { - RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "dict unpacking cannot be used in dict comprehension") } invalid_parameters: | a="/" ',' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one parameter must precede /") } @@ -1530,19 +1545,32 @@ invalid_class_def_raw: RAISE_INDENTATION_ERROR("expected an indented block after class definition on line %d", a->lineno) } invalid_double_starred_kvpairs: - | ','.double_starred_kvpair+ ',' invalid_kvpair - | expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") } + | invalid_kvpair_unpacking [','] + | ','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking) | expression a=':' &('}'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") } +invalid_kvpair_unpacking: + | a='**' b=if_expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid double starred expression. Did you forget to wrap the conditional expression in parentheses?") } + | a='*' b=bitwise_or ':' expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use a starred expression in a dictionary key") } + | a='**' b=bitwise_or ':' expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in a dictionary key") } + | expression ':' a='*' b=bitwise_or { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use a starred expression in a dictionary value") } + | expression ':' a='**' b=bitwise_or { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in a dictionary value") } invalid_kvpair: | a=expression !(':') { RAISE_ERROR_KNOWN_LOCATION(p, PyExc_SyntaxError, a->lineno, a->end_col_offset - 1, a->end_lineno, -1, "':' expected after dictionary key") } | expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") } + | expression ':' a='**' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use dict unpacking in a dictionary value") } | expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") } invalid_starred_expression_unpacking: + | a='*' b=if_expression { + RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid starred expression. Did you forget to wrap the conditional expression in parentheses?") } | a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") } +invalid_starred_expression_unpacking_sequence: + | a='**' bitwise_or { + RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use dict unpacking here") } + | invalid_starred_expression_unpacking invalid_starred_expression: | '*' { RAISE_SYNTAX_ERROR("Invalid star expression") } - invalid_fstring_replacement_field: | '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") } | '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") } diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 6f212d2f91e..7354f8281d9 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -337,7 +337,6 @@ def baz(): check('x=1\nfrom __future__ import division', 2, 1) check('foo(1=2)', 1, 5) check('def f():\n x, y: int', 2, 3) - check('[*x for x in xs]', 1, 2) check('foo(x for x in range(10), 100)', 1, 5) check('for 1 in []: pass', 1, 5) check('(yield i) = 2', 1, 2) @@ -2433,7 +2432,8 @@ def test_encodings(self): ) err = run_script(source.encode('cp437')) self.assertEqual(err[-3], ' "┬ó┬ó┬ó┬ó┬ó┬ó" + f(4, x for x in range(1))') - self.assertEqual(err[-2], ' ^^^') + self.assertEqual(err[-2], ' ^^^^^^^^^^^^^^^^^^^') + self.assertEqual(err[-1], 'SyntaxError: Generator expression must be parenthesized') # Check backwards tokenizer errors source = '# -*- coding: ascii -*-\n\n(\n' diff --git a/Lib/test/test_unpack_ex.py b/Lib/test/test_unpack_ex.py index 9e2d54bd3a8..d147cd96d20 100644 --- a/Lib/test/test_unpack_ex.py +++ b/Lib/test/test_unpack_ex.py @@ -141,7 +141,7 @@ >>> {0:1, **{0:2}, 0:3, 0:4} {0: 4} -List comprehension element unpacking +Comprehension element unpacking >>> a, b, c = [0, 1, 2], 3, 4 >>> [*a, b, c] @@ -149,46 +149,206 @@ >>> l = [a, (3, 4), {5}, {6: None}, (i for i in range(7, 10))] >>> [*item for item in l] - Traceback (most recent call last): - ... - SyntaxError: iterable unpacking cannot be used in comprehension + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - >>> [*[0, 1] for i in range(10)] - Traceback (most recent call last): - ... - SyntaxError: iterable unpacking cannot be used in comprehension + >>> [*[0, 1] for i in range(5)] + [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] - >>> [*'a' for i in range(10)] - Traceback (most recent call last): - ... - SyntaxError: iterable unpacking cannot be used in comprehension + >>> [*'a' for i in range(5)] + ['a', 'a', 'a', 'a', 'a'] >>> [*[] for i in range(10)] - Traceback (most recent call last): - ... - SyntaxError: iterable unpacking cannot be used in comprehension + [] + + >>> [*(x*2) for x in [[1, 2, 3], [], 'cat']] + [1, 2, 3, 1, 2, 3, 'c', 'a', 't', 'c', 'a', 't'] >>> {**{} for a in [1]} + {} + + >>> {**{7: i} for i in range(10)} + {7: 9} + + >>> dicts = [{1: 2}, {3: 4}, {5: 6, 7: 8}, {}, {9: 10}, {1: 0}] + >>> {**d for d in dicts} + {1: 0, 3: 4, 5: 6, 7: 8, 9: 10} + + >>> gen = (*(0, 1) for i in range(5)) + >>> next(gen) + 0 + >>> list(gen) + [1, 0, 1, 0, 1, 0, 1, 0, 1] + +Comprehension unpacking with conditionals and double loops + + >>> [*[i, i+1] for i in range(5) if i % 2 == 0] + [0, 1, 2, 3, 4, 5] + + >>> [*y for x in [[[0], [1, 2, 3], [], [4, 5]], [[6, 7]]] for y in x] + [0, 1, 2, 3, 4, 5, 6, 7] + + >>> [*y for x in [[[0], [1, 2, 3], [], [4, 5]], [[6, 7]]] for y in x if y and y[0]>0] + [1, 2, 3, 4, 5, 6, 7] + + >>> dicts = [{1: 2}, {3: 4}, {5: 6, 7: 8}, {}, {9: 10}, {1: 0}] + >>> {**d for d in dicts if len(d) != 2} + {1: 0, 3: 4, 9: 10} + +Scoping of assignment expressions in comprehensions + + >>> [*((y := i**2), 2*y) for i in range(4)] + [0, 0, 1, 2, 4, 8, 9, 18] + >>> y + 9 + + >>> [*(y := [i, i+1, i+2]) for i in range(4)] + [0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5] + >>> y + [3, 4, 5] + + >>> g = (*(z := [i, i+1, i+2]) for i in range(4)) + >>> z Traceback (most recent call last): ... - SyntaxError: dict unpacking cannot be used in dict comprehension + NameError: name 'z' is not defined + >>> next(g) + 0 + >>> z + [0, 1, 2] + >>> next(g) + 1 + >>> z + [0, 1, 2] + >>> next(g) + 2 + >>> z + [0, 1, 2] + >>> next(g) + 1 + >>> z + [1, 2, 3] -# Pegen is better here. -# Generator expression in function arguments + >>> x = [1, 2, 3] + >>> y = [4, 5, 6] + >>> def f(*args): + ... print(args) -# >>> list(*x for x in (range(5) for i in range(3))) -# Traceback (most recent call last): -# ... -# list(*x for x in (range(5) for i in range(3))) -# ^ -# SyntaxError: invalid syntax + >>> f(*x if x else y) + (1, 2, 3) + + +Malformed comperehension element unpacking + + >>> [*x for x in [1, 2, 3]] + Traceback (most recent call last): + ... + [*x for x in [1, 2, 3]] + ^^ + TypeError: Value after * must be an iterable, not int + + +Error messages for specific failure modes of unpacking + + >>> [*x if x else y for x in z] + Traceback (most recent call last): + ... + [*x if x else y for x in z] + ^^^^^^^^^^^^^^ + SyntaxError: invalid starred expression. Did you forget to wrap the conditional expression in parentheses? + + >>> [*x if x else y] + Traceback (most recent call last): + ... + [*x if x else y] + ^^^^^^^^^^^^^^ + SyntaxError: invalid starred expression. Did you forget to wrap the conditional expression in parentheses? + + >>> [x if x else *y for x in z] + Traceback (most recent call last): + ... + [x if x else *y for x in z] + ^ + SyntaxError: cannot unpack only part of a conditional expression + + >>> [x if x else *y] + Traceback (most recent call last): + ... + [x if x else *y] + ^ + SyntaxError: cannot unpack only part of a conditional expression + + >>> {**x if x else y} + Traceback (most recent call last): + ... + {**x if x else y} + ^^^^^^^^^^^^^^^^ + SyntaxError: invalid double starred expression. Did you forget to wrap the conditional expression in parentheses? + >>> {x if x else **y} + Traceback (most recent call last): + ... + {x if x else **y} + ^^ + SyntaxError: cannot use dict unpacking on only part of a conditional expression + + >>> [**x for x in [{1: 2}]] + Traceback (most recent call last): + ... + [**x for x in [{1: 2}]] + ^^^ + SyntaxError: cannot use dict unpacking in list comprehension + + >>> (**x for x in [{1:2}]) + Traceback (most recent call last): + ... + (**x for x in [{1:2}]) + ^^^ + SyntaxError: cannot use dict unpacking in generator expression >>> dict(**x for x in [{1:2}]) Traceback (most recent call last): ... dict(**x for x in [{1:2}]) - ^ - SyntaxError: invalid syntax + ^^^ + SyntaxError: cannot use dict unpacking in generator expression + + >>> {*a: b for a, b in {1: 2}.items()} + Traceback (most recent call last): + ... + {*a: b for a, b in {1: 2}.items()} + ^^ + SyntaxError: cannot use a starred expression in a dictionary key + + >>> {**a: b for a, b in {1: 2}.items()} + Traceback (most recent call last): + ... + {**a: b for a, b in {1: 2}.items()} + ^^^ + SyntaxError: cannot use dict unpacking in a dictionary key + + >>> {a: *b for a, b in {1: 2}.items()} + Traceback (most recent call last): + ... + {a: *b for a, b in {1: 2}.items()} + ^^ + SyntaxError: cannot use a starred expression in a dictionary value + + >>> {a: **b for a, b in {1: 2}.items()} + Traceback (most recent call last): + ... + {a: **b for a, b in {1: 2}.items()} + ^^^ + SyntaxError: cannot use dict unpacking in a dictionary value + + +# Generator expression in function arguments + + >>> list(*x for x in (range(5) for i in range(3))) + [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4] + + >>> def f(arg): + ... print(type(arg), list(arg), list(arg)) + >>> f(*x for x in [[1,2,3]]) + [1, 2, 3] [] Iterable argument unpacking diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-21-18-12-30.gh-issue-143055.PzwccL.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-21-18-12-30.gh-issue-143055.PzwccL.rst new file mode 100644 index 00000000000..d3ed40668f6 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-21-18-12-30.gh-issue-143055.PzwccL.rst @@ -0,0 +1 @@ +Implement :pep:`798` (Unpacking in Comprehensions). Patch by Adam Hartz. diff --git a/Parser/Python.asdl b/Parser/Python.asdl index 9c7529c4799..dbe226f8372 100644 --- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -67,7 +67,7 @@ module Python | Set(expr* elts) | ListComp(expr elt, comprehension* generators) | SetComp(expr elt, comprehension* generators) - | DictComp(expr key, expr value, comprehension* generators) + | DictComp(expr key, expr? value, comprehension* generators) | GeneratorExp(expr elt, comprehension* generators) -- the grammar constrains where yield expressions can occur | Await(expr value) diff --git a/Parser/parser.c b/Parser/parser.c index 09bfb5725a2..b9848a865b6 100644 --- a/Parser/parser.c +++ b/Parser/parser.c @@ -22,54 +22,54 @@ static KeywordToken *reserved_keywords[] = { (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) {{NULL, -1}}, (KeywordToken[]) { - {"if", 691}, - {"as", 689}, - {"in", 704}, + {"if", 695}, + {"as", 693}, + {"in", 708}, {"or", 589}, {"is", 597}, {NULL, -1}, }, (KeywordToken[]) { - {"del", 630}, - {"def", 708}, - {"for", 703}, - {"try", 665}, + {"del", 634}, + {"def", 712}, + {"for", 707}, + {"try", 669}, {"and", 590}, - {"not", 712}, + {"not", 716}, {NULL, -1}, }, (KeywordToken[]) { - {"from", 642}, + {"from", 646}, {"pass", 527}, - {"with", 656}, - {"elif", 696}, - {"else", 695}, - {"None", 624}, - {"True", 623}, + {"with", 660}, + {"elif", 700}, + {"else", 699}, + {"None", 628}, + {"True", 627}, {NULL, -1}, }, (KeywordToken[]) { - {"raise", 628}, + {"raise", 632}, {"yield", 588}, {"break", 528}, - {"async", 707}, - {"class", 710}, - {"while", 698}, - {"False", 625}, + {"async", 711}, + {"class", 714}, + {"while", 702}, + {"False", 629}, {"await", 598}, {NULL, -1}, }, (KeywordToken[]) { {"return", 522}, - {"import", 643}, - {"assert", 634}, + {"import", 647}, + {"assert", 638}, {"global", 530}, - {"except", 686}, + {"except", 690}, {"lambda", 622}, {NULL, -1}, }, (KeywordToken[]) { - {"finally", 682}, + {"finally", 686}, {NULL, -1}, }, (KeywordToken[]) { @@ -195,344 +195,352 @@ static char *soft_keywords[] = { #define type_param_starred_default_type 1107 #define expressions_type 1108 #define expression_type 1109 -#define yield_expr_type 1110 -#define star_expressions_type 1111 -#define star_expression_type 1112 -#define star_named_expressions_type 1113 -#define star_named_expression_type 1114 -#define assignment_expression_type 1115 -#define named_expression_type 1116 -#define disjunction_type 1117 -#define conjunction_type 1118 -#define inversion_type 1119 -#define comparison_type 1120 -#define compare_op_bitwise_or_pair_type 1121 -#define eq_bitwise_or_type 1122 -#define noteq_bitwise_or_type 1123 -#define lte_bitwise_or_type 1124 -#define lt_bitwise_or_type 1125 -#define gte_bitwise_or_type 1126 -#define gt_bitwise_or_type 1127 -#define notin_bitwise_or_type 1128 -#define in_bitwise_or_type 1129 -#define isnot_bitwise_or_type 1130 -#define is_bitwise_or_type 1131 -#define bitwise_or_type 1132 // Left-recursive -#define bitwise_xor_type 1133 // Left-recursive -#define bitwise_and_type 1134 // Left-recursive -#define shift_expr_type 1135 // Left-recursive -#define sum_type 1136 // Left-recursive -#define term_type 1137 // Left-recursive -#define factor_type 1138 -#define power_type 1139 -#define await_primary_type 1140 -#define primary_type 1141 // Left-recursive -#define slices_type 1142 -#define slice_type 1143 -#define atom_type 1144 -#define group_type 1145 -#define lambdef_type 1146 -#define lambda_params_type 1147 -#define lambda_parameters_type 1148 -#define lambda_slash_no_default_type 1149 -#define lambda_slash_with_default_type 1150 -#define lambda_star_etc_type 1151 -#define lambda_kwds_type 1152 -#define lambda_param_no_default_type 1153 -#define lambda_param_with_default_type 1154 -#define lambda_param_maybe_default_type 1155 -#define lambda_param_type 1156 -#define fstring_middle_type 1157 -#define fstring_replacement_field_type 1158 -#define fstring_conversion_type 1159 -#define fstring_full_format_spec_type 1160 -#define fstring_format_spec_type 1161 -#define fstring_type 1162 -#define tstring_format_spec_replacement_field_type 1163 -#define tstring_format_spec_type 1164 -#define tstring_full_format_spec_type 1165 -#define tstring_replacement_field_type 1166 -#define tstring_middle_type 1167 -#define tstring_type 1168 -#define string_type 1169 -#define strings_type 1170 -#define list_type 1171 -#define tuple_type 1172 -#define set_type 1173 -#define dict_type 1174 -#define double_starred_kvpairs_type 1175 -#define double_starred_kvpair_type 1176 -#define kvpair_type 1177 -#define for_if_clauses_type 1178 -#define for_if_clause_type 1179 -#define listcomp_type 1180 -#define setcomp_type 1181 -#define genexp_type 1182 -#define dictcomp_type 1183 -#define arguments_type 1184 -#define args_type 1185 -#define kwargs_type 1186 -#define starred_expression_type 1187 -#define kwarg_or_starred_type 1188 -#define kwarg_or_double_starred_type 1189 -#define star_targets_type 1190 -#define star_targets_list_seq_type 1191 -#define star_targets_tuple_seq_type 1192 -#define star_target_type 1193 -#define target_with_star_atom_type 1194 -#define star_atom_type 1195 -#define single_target_type 1196 -#define single_subscript_attribute_target_type 1197 -#define t_primary_type 1198 // Left-recursive -#define t_lookahead_type 1199 -#define del_targets_type 1200 -#define del_target_type 1201 -#define del_t_atom_type 1202 -#define type_expressions_type 1203 -#define func_type_comment_type 1204 -#define invalid_arguments_type 1205 -#define invalid_kwarg_type 1206 -#define expression_without_invalid_type 1207 -#define invalid_legacy_expression_type 1208 -#define invalid_type_param_type 1209 -#define invalid_expression_type 1210 -#define invalid_named_expression_type 1211 -#define invalid_assignment_type 1212 -#define invalid_ann_assign_target_type 1213 -#define invalid_raise_stmt_type 1214 -#define invalid_del_stmt_type 1215 -#define invalid_assert_stmt_type 1216 -#define invalid_block_type 1217 -#define invalid_comprehension_type 1218 -#define invalid_dict_comprehension_type 1219 -#define invalid_parameters_type 1220 -#define invalid_default_type 1221 -#define invalid_star_etc_type 1222 -#define invalid_kwds_type 1223 -#define invalid_parameters_helper_type 1224 -#define invalid_lambda_parameters_type 1225 -#define invalid_lambda_parameters_helper_type 1226 -#define invalid_lambda_star_etc_type 1227 -#define invalid_lambda_kwds_type 1228 -#define invalid_double_type_comments_type 1229 -#define invalid_with_item_type 1230 -#define invalid_for_if_clause_type 1231 -#define invalid_for_target_type 1232 -#define invalid_group_type 1233 -#define invalid_import_type 1234 -#define invalid_dotted_as_name_type 1235 -#define invalid_import_from_as_name_type 1236 -#define invalid_import_from_targets_type 1237 -#define invalid_with_stmt_type 1238 -#define invalid_with_stmt_indent_type 1239 -#define invalid_try_stmt_type 1240 -#define invalid_except_stmt_type 1241 -#define invalid_except_star_stmt_type 1242 -#define invalid_finally_stmt_type 1243 -#define invalid_except_stmt_indent_type 1244 -#define invalid_except_star_stmt_indent_type 1245 -#define invalid_match_stmt_type 1246 -#define invalid_case_block_type 1247 -#define invalid_as_pattern_type 1248 -#define invalid_class_pattern_type 1249 -#define invalid_mapping_pattern_type 1250 -#define invalid_class_argument_pattern_type 1251 -#define invalid_if_stmt_type 1252 -#define invalid_elif_stmt_type 1253 -#define invalid_else_stmt_type 1254 -#define invalid_while_stmt_type 1255 -#define invalid_for_stmt_type 1256 -#define invalid_def_raw_type 1257 -#define invalid_class_def_raw_type 1258 -#define invalid_double_starred_kvpairs_type 1259 -#define invalid_kvpair_type 1260 -#define invalid_starred_expression_unpacking_type 1261 -#define invalid_starred_expression_type 1262 -#define invalid_fstring_replacement_field_type 1263 -#define invalid_fstring_conversion_character_type 1264 -#define invalid_tstring_replacement_field_type 1265 -#define invalid_tstring_conversion_character_type 1266 -#define invalid_string_tstring_concat_type 1267 -#define invalid_arithmetic_type 1268 -#define invalid_factor_type 1269 -#define invalid_type_params_type 1270 -#define _loop0_1_type 1271 -#define _loop1_2_type 1272 -#define _loop0_3_type 1273 -#define _gather_4_type 1274 -#define _tmp_5_type 1275 -#define _tmp_6_type 1276 -#define _tmp_7_type 1277 -#define _tmp_8_type 1278 -#define _tmp_9_type 1279 -#define _tmp_10_type 1280 -#define _tmp_11_type 1281 -#define _loop1_12_type 1282 -#define _loop0_13_type 1283 -#define _gather_14_type 1284 -#define _tmp_15_type 1285 -#define _tmp_16_type 1286 -#define _loop0_17_type 1287 -#define _loop1_18_type 1288 -#define _loop0_19_type 1289 -#define _gather_20_type 1290 -#define _tmp_21_type 1291 -#define _loop0_22_type 1292 -#define _gather_23_type 1293 -#define _loop1_24_type 1294 -#define _tmp_25_type 1295 -#define _tmp_26_type 1296 -#define _loop0_27_type 1297 -#define _loop0_28_type 1298 -#define _loop1_29_type 1299 -#define _loop1_30_type 1300 -#define _loop0_31_type 1301 -#define _loop1_32_type 1302 -#define _loop0_33_type 1303 -#define _gather_34_type 1304 -#define _tmp_35_type 1305 -#define _loop1_36_type 1306 -#define _loop1_37_type 1307 -#define _loop1_38_type 1308 -#define _loop0_39_type 1309 -#define _gather_40_type 1310 -#define _tmp_41_type 1311 -#define _tmp_42_type 1312 -#define _tmp_43_type 1313 -#define _loop0_44_type 1314 -#define _gather_45_type 1315 -#define _loop0_46_type 1316 -#define _gather_47_type 1317 -#define _tmp_48_type 1318 -#define _loop0_49_type 1319 -#define _gather_50_type 1320 -#define _loop0_51_type 1321 -#define _gather_52_type 1322 -#define _loop0_53_type 1323 -#define _gather_54_type 1324 -#define _loop1_55_type 1325 -#define _loop1_56_type 1326 -#define _loop0_57_type 1327 -#define _gather_58_type 1328 -#define _loop1_59_type 1329 -#define _loop1_60_type 1330 -#define _loop1_61_type 1331 -#define _tmp_62_type 1332 -#define _loop0_63_type 1333 -#define _gather_64_type 1334 -#define _tmp_65_type 1335 -#define _tmp_66_type 1336 -#define _tmp_67_type 1337 -#define _tmp_68_type 1338 -#define _tmp_69_type 1339 -#define _loop0_70_type 1340 -#define _loop0_71_type 1341 -#define _loop1_72_type 1342 -#define _loop1_73_type 1343 -#define _loop0_74_type 1344 -#define _loop1_75_type 1345 -#define _loop0_76_type 1346 -#define _loop0_77_type 1347 -#define _loop0_78_type 1348 -#define _loop0_79_type 1349 -#define _loop1_80_type 1350 -#define _loop1_81_type 1351 -#define _tmp_82_type 1352 -#define _loop0_83_type 1353 -#define _gather_84_type 1354 -#define _loop1_85_type 1355 -#define _loop0_86_type 1356 -#define _tmp_87_type 1357 -#define _loop0_88_type 1358 -#define _gather_89_type 1359 -#define _tmp_90_type 1360 -#define _loop0_91_type 1361 -#define _gather_92_type 1362 -#define _loop0_93_type 1363 -#define _gather_94_type 1364 -#define _loop0_95_type 1365 -#define _loop0_96_type 1366 -#define _gather_97_type 1367 -#define _loop1_98_type 1368 -#define _tmp_99_type 1369 -#define _loop0_100_type 1370 -#define _gather_101_type 1371 -#define _loop0_102_type 1372 -#define _gather_103_type 1373 -#define _tmp_104_type 1374 -#define _tmp_105_type 1375 -#define _loop0_106_type 1376 -#define _gather_107_type 1377 -#define _tmp_108_type 1378 -#define _tmp_109_type 1379 -#define _tmp_110_type 1380 -#define _tmp_111_type 1381 -#define _tmp_112_type 1382 -#define _loop1_113_type 1383 -#define _tmp_114_type 1384 -#define _tmp_115_type 1385 -#define _tmp_116_type 1386 -#define _tmp_117_type 1387 -#define _tmp_118_type 1388 -#define _loop0_119_type 1389 -#define _loop0_120_type 1390 -#define _tmp_121_type 1391 -#define _tmp_122_type 1392 -#define _tmp_123_type 1393 -#define _tmp_124_type 1394 -#define _tmp_125_type 1395 -#define _tmp_126_type 1396 -#define _tmp_127_type 1397 -#define _tmp_128_type 1398 -#define _tmp_129_type 1399 -#define _loop0_130_type 1400 -#define _gather_131_type 1401 -#define _tmp_132_type 1402 -#define _tmp_133_type 1403 -#define _tmp_134_type 1404 -#define _tmp_135_type 1405 -#define _loop0_136_type 1406 -#define _gather_137_type 1407 -#define _tmp_138_type 1408 -#define _loop0_139_type 1409 -#define _gather_140_type 1410 -#define _loop0_141_type 1411 -#define _gather_142_type 1412 -#define _tmp_143_type 1413 -#define _loop0_144_type 1414 -#define _tmp_145_type 1415 -#define _tmp_146_type 1416 -#define _tmp_147_type 1417 -#define _tmp_148_type 1418 -#define _tmp_149_type 1419 -#define _tmp_150_type 1420 -#define _tmp_151_type 1421 -#define _tmp_152_type 1422 -#define _tmp_153_type 1423 -#define _tmp_154_type 1424 -#define _tmp_155_type 1425 -#define _tmp_156_type 1426 -#define _tmp_157_type 1427 -#define _tmp_158_type 1428 -#define _tmp_159_type 1429 -#define _tmp_160_type 1430 -#define _tmp_161_type 1431 -#define _tmp_162_type 1432 -#define _tmp_163_type 1433 -#define _tmp_164_type 1434 -#define _tmp_165_type 1435 -#define _tmp_166_type 1436 -#define _tmp_167_type 1437 -#define _tmp_168_type 1438 -#define _tmp_169_type 1439 -#define _tmp_170_type 1440 -#define _tmp_171_type 1441 -#define _loop0_172_type 1442 -#define _tmp_173_type 1443 -#define _tmp_174_type 1444 -#define _tmp_175_type 1445 -#define _tmp_176_type 1446 -#define _tmp_177_type 1447 +#define if_expression_type 1110 +#define yield_expr_type 1111 +#define star_expressions_type 1112 +#define star_expression_type 1113 +#define star_named_expressions_type 1114 +#define star_named_expressions_sequence_type 1115 +#define star_named_expression_type 1116 +#define star_named_expression_sequence_type 1117 +#define assignment_expression_type 1118 +#define named_expression_type 1119 +#define disjunction_type 1120 +#define conjunction_type 1121 +#define inversion_type 1122 +#define comparison_type 1123 +#define compare_op_bitwise_or_pair_type 1124 +#define eq_bitwise_or_type 1125 +#define noteq_bitwise_or_type 1126 +#define lte_bitwise_or_type 1127 +#define lt_bitwise_or_type 1128 +#define gte_bitwise_or_type 1129 +#define gt_bitwise_or_type 1130 +#define notin_bitwise_or_type 1131 +#define in_bitwise_or_type 1132 +#define isnot_bitwise_or_type 1133 +#define is_bitwise_or_type 1134 +#define bitwise_or_type 1135 // Left-recursive +#define bitwise_xor_type 1136 // Left-recursive +#define bitwise_and_type 1137 // Left-recursive +#define shift_expr_type 1138 // Left-recursive +#define sum_type 1139 // Left-recursive +#define term_type 1140 // Left-recursive +#define factor_type 1141 +#define power_type 1142 +#define await_primary_type 1143 +#define primary_type 1144 // Left-recursive +#define slices_type 1145 +#define slice_type 1146 +#define atom_type 1147 +#define group_type 1148 +#define lambdef_type 1149 +#define lambda_params_type 1150 +#define lambda_parameters_type 1151 +#define lambda_slash_no_default_type 1152 +#define lambda_slash_with_default_type 1153 +#define lambda_star_etc_type 1154 +#define lambda_kwds_type 1155 +#define lambda_param_no_default_type 1156 +#define lambda_param_with_default_type 1157 +#define lambda_param_maybe_default_type 1158 +#define lambda_param_type 1159 +#define fstring_middle_type 1160 +#define fstring_replacement_field_type 1161 +#define fstring_conversion_type 1162 +#define fstring_full_format_spec_type 1163 +#define fstring_format_spec_type 1164 +#define fstring_type 1165 +#define tstring_format_spec_replacement_field_type 1166 +#define tstring_format_spec_type 1167 +#define tstring_full_format_spec_type 1168 +#define tstring_replacement_field_type 1169 +#define tstring_middle_type 1170 +#define tstring_type 1171 +#define string_type 1172 +#define strings_type 1173 +#define list_type 1174 +#define tuple_type 1175 +#define set_type 1176 +#define dict_type 1177 +#define double_starred_kvpairs_type 1178 +#define double_starred_kvpair_type 1179 +#define kvpair_type 1180 +#define for_if_clauses_type 1181 +#define for_if_clause_type 1182 +#define listcomp_type 1183 +#define setcomp_type 1184 +#define genexp_type 1185 +#define dictcomp_type 1186 +#define arguments_type 1187 +#define args_type 1188 +#define kwargs_type 1189 +#define starred_expression_type 1190 +#define kwarg_or_starred_type 1191 +#define kwarg_or_double_starred_type 1192 +#define star_targets_type 1193 +#define star_targets_list_seq_type 1194 +#define star_targets_tuple_seq_type 1195 +#define star_target_type 1196 +#define target_with_star_atom_type 1197 +#define star_atom_type 1198 +#define single_target_type 1199 +#define single_subscript_attribute_target_type 1200 +#define t_primary_type 1201 // Left-recursive +#define t_lookahead_type 1202 +#define del_targets_type 1203 +#define del_target_type 1204 +#define del_t_atom_type 1205 +#define type_expressions_type 1206 +#define func_type_comment_type 1207 +#define invalid_arguments_type 1208 +#define invalid_kwarg_type 1209 +#define expression_without_invalid_type 1210 +#define invalid_legacy_expression_type 1211 +#define invalid_type_param_type 1212 +#define invalid_expression_type 1213 +#define invalid_if_expression_type 1214 +#define invalid_named_expression_type 1215 +#define invalid_assignment_type 1216 +#define invalid_ann_assign_target_type 1217 +#define invalid_raise_stmt_type 1218 +#define invalid_del_stmt_type 1219 +#define invalid_assert_stmt_type 1220 +#define invalid_block_type 1221 +#define invalid_comprehension_type 1222 +#define invalid_parameters_type 1223 +#define invalid_default_type 1224 +#define invalid_star_etc_type 1225 +#define invalid_kwds_type 1226 +#define invalid_parameters_helper_type 1227 +#define invalid_lambda_parameters_type 1228 +#define invalid_lambda_parameters_helper_type 1229 +#define invalid_lambda_star_etc_type 1230 +#define invalid_lambda_kwds_type 1231 +#define invalid_double_type_comments_type 1232 +#define invalid_with_item_type 1233 +#define invalid_for_if_clause_type 1234 +#define invalid_for_target_type 1235 +#define invalid_group_type 1236 +#define invalid_import_type 1237 +#define invalid_dotted_as_name_type 1238 +#define invalid_import_from_as_name_type 1239 +#define invalid_import_from_targets_type 1240 +#define invalid_with_stmt_type 1241 +#define invalid_with_stmt_indent_type 1242 +#define invalid_try_stmt_type 1243 +#define invalid_except_stmt_type 1244 +#define invalid_except_star_stmt_type 1245 +#define invalid_finally_stmt_type 1246 +#define invalid_except_stmt_indent_type 1247 +#define invalid_except_star_stmt_indent_type 1248 +#define invalid_match_stmt_type 1249 +#define invalid_case_block_type 1250 +#define invalid_as_pattern_type 1251 +#define invalid_class_pattern_type 1252 +#define invalid_mapping_pattern_type 1253 +#define invalid_class_argument_pattern_type 1254 +#define invalid_if_stmt_type 1255 +#define invalid_elif_stmt_type 1256 +#define invalid_else_stmt_type 1257 +#define invalid_while_stmt_type 1258 +#define invalid_for_stmt_type 1259 +#define invalid_def_raw_type 1260 +#define invalid_class_def_raw_type 1261 +#define invalid_double_starred_kvpairs_type 1262 +#define invalid_kvpair_unpacking_type 1263 +#define invalid_kvpair_type 1264 +#define invalid_starred_expression_unpacking_type 1265 +#define invalid_starred_expression_unpacking_sequence_type 1266 +#define invalid_starred_expression_type 1267 +#define invalid_fstring_replacement_field_type 1268 +#define invalid_fstring_conversion_character_type 1269 +#define invalid_tstring_replacement_field_type 1270 +#define invalid_tstring_conversion_character_type 1271 +#define invalid_string_tstring_concat_type 1272 +#define invalid_arithmetic_type 1273 +#define invalid_factor_type 1274 +#define invalid_type_params_type 1275 +#define _loop0_1_type 1276 +#define _loop1_2_type 1277 +#define _loop0_3_type 1278 +#define _gather_4_type 1279 +#define _tmp_5_type 1280 +#define _tmp_6_type 1281 +#define _tmp_7_type 1282 +#define _tmp_8_type 1283 +#define _tmp_9_type 1284 +#define _tmp_10_type 1285 +#define _tmp_11_type 1286 +#define _loop1_12_type 1287 +#define _loop0_13_type 1288 +#define _gather_14_type 1289 +#define _tmp_15_type 1290 +#define _tmp_16_type 1291 +#define _loop0_17_type 1292 +#define _loop1_18_type 1293 +#define _loop0_19_type 1294 +#define _gather_20_type 1295 +#define _tmp_21_type 1296 +#define _loop0_22_type 1297 +#define _gather_23_type 1298 +#define _loop1_24_type 1299 +#define _tmp_25_type 1300 +#define _tmp_26_type 1301 +#define _loop0_27_type 1302 +#define _loop0_28_type 1303 +#define _loop1_29_type 1304 +#define _loop1_30_type 1305 +#define _loop0_31_type 1306 +#define _loop1_32_type 1307 +#define _loop0_33_type 1308 +#define _gather_34_type 1309 +#define _tmp_35_type 1310 +#define _loop1_36_type 1311 +#define _loop1_37_type 1312 +#define _loop1_38_type 1313 +#define _loop0_39_type 1314 +#define _gather_40_type 1315 +#define _tmp_41_type 1316 +#define _tmp_42_type 1317 +#define _tmp_43_type 1318 +#define _loop0_44_type 1319 +#define _gather_45_type 1320 +#define _loop0_46_type 1321 +#define _gather_47_type 1322 +#define _tmp_48_type 1323 +#define _loop0_49_type 1324 +#define _gather_50_type 1325 +#define _loop0_51_type 1326 +#define _gather_52_type 1327 +#define _loop0_53_type 1328 +#define _gather_54_type 1329 +#define _loop1_55_type 1330 +#define _loop1_56_type 1331 +#define _loop0_57_type 1332 +#define _gather_58_type 1333 +#define _loop0_59_type 1334 +#define _gather_60_type 1335 +#define _loop1_61_type 1336 +#define _loop1_62_type 1337 +#define _loop1_63_type 1338 +#define _tmp_64_type 1339 +#define _loop0_65_type 1340 +#define _gather_66_type 1341 +#define _tmp_67_type 1342 +#define _tmp_68_type 1343 +#define _tmp_69_type 1344 +#define _tmp_70_type 1345 +#define _tmp_71_type 1346 +#define _loop0_72_type 1347 +#define _loop0_73_type 1348 +#define _loop1_74_type 1349 +#define _loop1_75_type 1350 +#define _loop0_76_type 1351 +#define _loop1_77_type 1352 +#define _loop0_78_type 1353 +#define _loop0_79_type 1354 +#define _loop0_80_type 1355 +#define _loop0_81_type 1356 +#define _loop1_82_type 1357 +#define _loop1_83_type 1358 +#define _tmp_84_type 1359 +#define _loop0_85_type 1360 +#define _gather_86_type 1361 +#define _loop1_87_type 1362 +#define _loop0_88_type 1363 +#define _tmp_89_type 1364 +#define _loop0_90_type 1365 +#define _gather_91_type 1366 +#define _tmp_92_type 1367 +#define _loop0_93_type 1368 +#define _gather_94_type 1369 +#define _loop0_95_type 1370 +#define _gather_96_type 1371 +#define _loop0_97_type 1372 +#define _loop0_98_type 1373 +#define _gather_99_type 1374 +#define _loop1_100_type 1375 +#define _tmp_101_type 1376 +#define _loop0_102_type 1377 +#define _gather_103_type 1378 +#define _loop0_104_type 1379 +#define _gather_105_type 1380 +#define _tmp_106_type 1381 +#define _tmp_107_type 1382 +#define _loop0_108_type 1383 +#define _gather_109_type 1384 +#define _tmp_110_type 1385 +#define _tmp_111_type 1386 +#define _tmp_112_type 1387 +#define _tmp_113_type 1388 +#define _tmp_114_type 1389 +#define _loop1_115_type 1390 +#define _tmp_116_type 1391 +#define _tmp_117_type 1392 +#define _tmp_118_type 1393 +#define _tmp_119_type 1394 +#define _tmp_120_type 1395 +#define _loop0_121_type 1396 +#define _loop0_122_type 1397 +#define _tmp_123_type 1398 +#define _tmp_124_type 1399 +#define _tmp_125_type 1400 +#define _tmp_126_type 1401 +#define _tmp_127_type 1402 +#define _tmp_128_type 1403 +#define _tmp_129_type 1404 +#define _tmp_130_type 1405 +#define _loop0_131_type 1406 +#define _gather_132_type 1407 +#define _tmp_133_type 1408 +#define _tmp_134_type 1409 +#define _tmp_135_type 1410 +#define _tmp_136_type 1411 +#define _loop0_137_type 1412 +#define _gather_138_type 1413 +#define _tmp_139_type 1414 +#define _loop0_140_type 1415 +#define _gather_141_type 1416 +#define _loop0_142_type 1417 +#define _gather_143_type 1418 +#define _tmp_144_type 1419 +#define _loop0_145_type 1420 +#define _tmp_146_type 1421 +#define _tmp_147_type 1422 +#define _tmp_148_type 1423 +#define _tmp_149_type 1424 +#define _tmp_150_type 1425 +#define _tmp_151_type 1426 +#define _tmp_152_type 1427 +#define _tmp_153_type 1428 +#define _tmp_154_type 1429 +#define _tmp_155_type 1430 +#define _tmp_156_type 1431 +#define _tmp_157_type 1432 +#define _tmp_158_type 1433 +#define _tmp_159_type 1434 +#define _tmp_160_type 1435 +#define _tmp_161_type 1436 +#define _tmp_162_type 1437 +#define _tmp_163_type 1438 +#define _tmp_164_type 1439 +#define _tmp_165_type 1440 +#define _tmp_166_type 1441 +#define _tmp_167_type 1442 +#define _tmp_168_type 1443 +#define _tmp_169_type 1444 +#define _tmp_170_type 1445 +#define _tmp_171_type 1446 +#define _tmp_172_type 1447 +#define _tmp_173_type 1448 +#define _loop0_174_type 1449 +#define _tmp_175_type 1450 +#define _tmp_176_type 1451 +#define _tmp_177_type 1452 +#define _tmp_178_type 1453 +#define _tmp_179_type 1454 +#define _tmp_180_type 1455 static mod_ty file_rule(Parser *p); static mod_ty interactive_rule(Parser *p); @@ -644,11 +652,14 @@ static expr_ty type_param_default_rule(Parser *p); static expr_ty type_param_starred_default_rule(Parser *p); static expr_ty expressions_rule(Parser *p); static expr_ty expression_rule(Parser *p); +static expr_ty if_expression_rule(Parser *p); static expr_ty yield_expr_rule(Parser *p); static expr_ty star_expressions_rule(Parser *p); static expr_ty star_expression_rule(Parser *p); static asdl_expr_seq* star_named_expressions_rule(Parser *p); +static asdl_expr_seq* star_named_expressions_sequence_rule(Parser *p); static expr_ty star_named_expression_rule(Parser *p); +static expr_ty star_named_expression_sequence_rule(Parser *p); static expr_ty assignment_expression_rule(Parser *p); static expr_ty named_expression_rule(Parser *p); static expr_ty disjunction_rule(Parser *p); @@ -745,6 +756,7 @@ static expr_ty expression_without_invalid_rule(Parser *p); static void *invalid_legacy_expression_rule(Parser *p); static void *invalid_type_param_rule(Parser *p); static void *invalid_expression_rule(Parser *p); +static void *invalid_if_expression_rule(Parser *p); static void *invalid_named_expression_rule(Parser *p); static void *invalid_assignment_rule(Parser *p); static expr_ty invalid_ann_assign_target_rule(Parser *p); @@ -753,7 +765,6 @@ static void *invalid_del_stmt_rule(Parser *p); static void *invalid_assert_stmt_rule(Parser *p); static void *invalid_block_rule(Parser *p); static void *invalid_comprehension_rule(Parser *p); -static void *invalid_dict_comprehension_rule(Parser *p); static void *invalid_parameters_rule(Parser *p); static void *invalid_default_rule(Parser *p); static void *invalid_star_etc_rule(Parser *p); @@ -794,8 +805,10 @@ static void *invalid_for_stmt_rule(Parser *p); static void *invalid_def_raw_rule(Parser *p); static void *invalid_class_def_raw_rule(Parser *p); static void *invalid_double_starred_kvpairs_rule(Parser *p); +static void *invalid_kvpair_unpacking_rule(Parser *p); static void *invalid_kvpair_rule(Parser *p); static void *invalid_starred_expression_unpacking_rule(Parser *p); +static void *invalid_starred_expression_unpacking_sequence_rule(Parser *p); static void *invalid_starred_expression_rule(Parser *p); static void *invalid_fstring_replacement_field_rule(Parser *p); static void *invalid_fstring_conversion_character_rule(Parser *p); @@ -863,70 +876,70 @@ static asdl_seq *_loop1_55_rule(Parser *p); static asdl_seq *_loop1_56_rule(Parser *p); static asdl_seq *_loop0_57_rule(Parser *p); static asdl_seq *_gather_58_rule(Parser *p); -static asdl_seq *_loop1_59_rule(Parser *p); -static asdl_seq *_loop1_60_rule(Parser *p); +static asdl_seq *_loop0_59_rule(Parser *p); +static asdl_seq *_gather_60_rule(Parser *p); static asdl_seq *_loop1_61_rule(Parser *p); -static void *_tmp_62_rule(Parser *p); -static asdl_seq *_loop0_63_rule(Parser *p); -static asdl_seq *_gather_64_rule(Parser *p); -static void *_tmp_65_rule(Parser *p); -static void *_tmp_66_rule(Parser *p); +static asdl_seq *_loop1_62_rule(Parser *p); +static asdl_seq *_loop1_63_rule(Parser *p); +static void *_tmp_64_rule(Parser *p); +static asdl_seq *_loop0_65_rule(Parser *p); +static asdl_seq *_gather_66_rule(Parser *p); static void *_tmp_67_rule(Parser *p); static void *_tmp_68_rule(Parser *p); static void *_tmp_69_rule(Parser *p); -static asdl_seq *_loop0_70_rule(Parser *p); -static asdl_seq *_loop0_71_rule(Parser *p); -static asdl_seq *_loop1_72_rule(Parser *p); -static asdl_seq *_loop1_73_rule(Parser *p); -static asdl_seq *_loop0_74_rule(Parser *p); +static void *_tmp_70_rule(Parser *p); +static void *_tmp_71_rule(Parser *p); +static asdl_seq *_loop0_72_rule(Parser *p); +static asdl_seq *_loop0_73_rule(Parser *p); +static asdl_seq *_loop1_74_rule(Parser *p); static asdl_seq *_loop1_75_rule(Parser *p); static asdl_seq *_loop0_76_rule(Parser *p); -static asdl_seq *_loop0_77_rule(Parser *p); +static asdl_seq *_loop1_77_rule(Parser *p); static asdl_seq *_loop0_78_rule(Parser *p); static asdl_seq *_loop0_79_rule(Parser *p); -static asdl_seq *_loop1_80_rule(Parser *p); -static asdl_seq *_loop1_81_rule(Parser *p); -static void *_tmp_82_rule(Parser *p); -static asdl_seq *_loop0_83_rule(Parser *p); -static asdl_seq *_gather_84_rule(Parser *p); -static asdl_seq *_loop1_85_rule(Parser *p); -static asdl_seq *_loop0_86_rule(Parser *p); -static void *_tmp_87_rule(Parser *p); +static asdl_seq *_loop0_80_rule(Parser *p); +static asdl_seq *_loop0_81_rule(Parser *p); +static asdl_seq *_loop1_82_rule(Parser *p); +static asdl_seq *_loop1_83_rule(Parser *p); +static void *_tmp_84_rule(Parser *p); +static asdl_seq *_loop0_85_rule(Parser *p); +static asdl_seq *_gather_86_rule(Parser *p); +static asdl_seq *_loop1_87_rule(Parser *p); static asdl_seq *_loop0_88_rule(Parser *p); -static asdl_seq *_gather_89_rule(Parser *p); -static void *_tmp_90_rule(Parser *p); -static asdl_seq *_loop0_91_rule(Parser *p); -static asdl_seq *_gather_92_rule(Parser *p); +static void *_tmp_89_rule(Parser *p); +static asdl_seq *_loop0_90_rule(Parser *p); +static asdl_seq *_gather_91_rule(Parser *p); +static void *_tmp_92_rule(Parser *p); static asdl_seq *_loop0_93_rule(Parser *p); static asdl_seq *_gather_94_rule(Parser *p); static asdl_seq *_loop0_95_rule(Parser *p); -static asdl_seq *_loop0_96_rule(Parser *p); -static asdl_seq *_gather_97_rule(Parser *p); -static asdl_seq *_loop1_98_rule(Parser *p); -static void *_tmp_99_rule(Parser *p); -static asdl_seq *_loop0_100_rule(Parser *p); -static asdl_seq *_gather_101_rule(Parser *p); +static asdl_seq *_gather_96_rule(Parser *p); +static asdl_seq *_loop0_97_rule(Parser *p); +static asdl_seq *_loop0_98_rule(Parser *p); +static asdl_seq *_gather_99_rule(Parser *p); +static asdl_seq *_loop1_100_rule(Parser *p); +static void *_tmp_101_rule(Parser *p); static asdl_seq *_loop0_102_rule(Parser *p); static asdl_seq *_gather_103_rule(Parser *p); -static void *_tmp_104_rule(Parser *p); -static void *_tmp_105_rule(Parser *p); -static asdl_seq *_loop0_106_rule(Parser *p); -static asdl_seq *_gather_107_rule(Parser *p); -static void *_tmp_108_rule(Parser *p); -static void *_tmp_109_rule(Parser *p); +static asdl_seq *_loop0_104_rule(Parser *p); +static asdl_seq *_gather_105_rule(Parser *p); +static void *_tmp_106_rule(Parser *p); +static void *_tmp_107_rule(Parser *p); +static asdl_seq *_loop0_108_rule(Parser *p); +static asdl_seq *_gather_109_rule(Parser *p); static void *_tmp_110_rule(Parser *p); static void *_tmp_111_rule(Parser *p); static void *_tmp_112_rule(Parser *p); -static asdl_seq *_loop1_113_rule(Parser *p); +static void *_tmp_113_rule(Parser *p); static void *_tmp_114_rule(Parser *p); -static void *_tmp_115_rule(Parser *p); +static asdl_seq *_loop1_115_rule(Parser *p); static void *_tmp_116_rule(Parser *p); static void *_tmp_117_rule(Parser *p); static void *_tmp_118_rule(Parser *p); -static asdl_seq *_loop0_119_rule(Parser *p); -static asdl_seq *_loop0_120_rule(Parser *p); -static void *_tmp_121_rule(Parser *p); -static void *_tmp_122_rule(Parser *p); +static void *_tmp_119_rule(Parser *p); +static void *_tmp_120_rule(Parser *p); +static asdl_seq *_loop0_121_rule(Parser *p); +static asdl_seq *_loop0_122_rule(Parser *p); static void *_tmp_123_rule(Parser *p); static void *_tmp_124_rule(Parser *p); static void *_tmp_125_rule(Parser *p); @@ -934,22 +947,22 @@ static void *_tmp_126_rule(Parser *p); static void *_tmp_127_rule(Parser *p); static void *_tmp_128_rule(Parser *p); static void *_tmp_129_rule(Parser *p); -static asdl_seq *_loop0_130_rule(Parser *p); -static asdl_seq *_gather_131_rule(Parser *p); -static void *_tmp_132_rule(Parser *p); +static void *_tmp_130_rule(Parser *p); +static asdl_seq *_loop0_131_rule(Parser *p); +static asdl_seq *_gather_132_rule(Parser *p); static void *_tmp_133_rule(Parser *p); static void *_tmp_134_rule(Parser *p); static void *_tmp_135_rule(Parser *p); -static asdl_seq *_loop0_136_rule(Parser *p); -static asdl_seq *_gather_137_rule(Parser *p); -static void *_tmp_138_rule(Parser *p); -static asdl_seq *_loop0_139_rule(Parser *p); -static asdl_seq *_gather_140_rule(Parser *p); -static asdl_seq *_loop0_141_rule(Parser *p); -static asdl_seq *_gather_142_rule(Parser *p); -static void *_tmp_143_rule(Parser *p); -static asdl_seq *_loop0_144_rule(Parser *p); -static void *_tmp_145_rule(Parser *p); +static void *_tmp_136_rule(Parser *p); +static asdl_seq *_loop0_137_rule(Parser *p); +static asdl_seq *_gather_138_rule(Parser *p); +static void *_tmp_139_rule(Parser *p); +static asdl_seq *_loop0_140_rule(Parser *p); +static asdl_seq *_gather_141_rule(Parser *p); +static asdl_seq *_loop0_142_rule(Parser *p); +static asdl_seq *_gather_143_rule(Parser *p); +static void *_tmp_144_rule(Parser *p); +static asdl_seq *_loop0_145_rule(Parser *p); static void *_tmp_146_rule(Parser *p); static void *_tmp_147_rule(Parser *p); static void *_tmp_148_rule(Parser *p); @@ -976,12 +989,15 @@ static void *_tmp_168_rule(Parser *p); static void *_tmp_169_rule(Parser *p); static void *_tmp_170_rule(Parser *p); static void *_tmp_171_rule(Parser *p); -static asdl_seq *_loop0_172_rule(Parser *p); +static void *_tmp_172_rule(Parser *p); static void *_tmp_173_rule(Parser *p); -static void *_tmp_174_rule(Parser *p); +static asdl_seq *_loop0_174_rule(Parser *p); static void *_tmp_175_rule(Parser *p); static void *_tmp_176_rule(Parser *p); static void *_tmp_177_rule(Parser *p); +static void *_tmp_178_rule(Parser *p); +static void *_tmp_179_rule(Parser *p); +static void *_tmp_180_rule(Parser *p); // file: statements? $ @@ -1709,7 +1725,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'raise' raise_stmt")); stmt_ty raise_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 628) // token='raise' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 632) // token='raise' && (raise_stmt_var = raise_stmt_rule(p)) // raise_stmt ) @@ -1751,7 +1767,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'del' del_stmt")); stmt_ty del_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 630) // token='del' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 634) // token='del' && (del_stmt_var = del_stmt_rule(p)) // del_stmt ) @@ -1793,7 +1809,7 @@ simple_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'assert' assert_stmt")); stmt_ty assert_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 634) // token='assert' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 638) // token='assert' && (assert_stmt_var = assert_stmt_rule(p)) // assert_stmt ) @@ -1947,7 +1963,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt")); stmt_ty if_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 691) // token='if' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 695) // token='if' && (if_stmt_var = if_stmt_rule(p)) // if_stmt ) @@ -2031,7 +2047,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt")); stmt_ty try_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 665) // token='try' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 669) // token='try' && (try_stmt_var = try_stmt_rule(p)) // try_stmt ) @@ -2052,7 +2068,7 @@ compound_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt")); stmt_ty while_stmt_var; if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 698) // token='while' + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 702) // token='while' && (while_stmt_var = while_stmt_rule(p)) // while_stmt ) @@ -2815,11 +2831,11 @@ raise_stmt_rule(Parser *p) expr_ty a; expr_ty b; if ( - (_keyword = _PyPegen_expect_token(p, 628)) // token='raise' + (_keyword = _PyPegen_expect_token(p, 632)) // token='raise' && (a = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' && (b = expression_rule(p)) // expression ) @@ -2874,7 +2890,7 @@ raise_stmt_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 628)) // token='raise' + (_keyword = _PyPegen_expect_token(p, 632)) // token='raise' && (a = expression_rule(p)) // expression ) @@ -2909,7 +2925,7 @@ raise_stmt_rule(Parser *p) D(fprintf(stderr, "%*c> raise_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'raise'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 628)) // token='raise' + (_keyword = _PyPegen_expect_token(p, 632)) // token='raise' ) { D(fprintf(stderr, "%*c+ raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise'")); @@ -3282,7 +3298,7 @@ del_stmt_rule(Parser *p) Token * _keyword; asdl_expr_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 630)) // token='del' + (_keyword = _PyPegen_expect_token(p, 634)) // token='del' && (a = del_targets_rule(p)) // del_targets && @@ -3448,7 +3464,7 @@ assert_stmt_rule(Parser *p) expr_ty a; void *b; if ( - (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 638)) // token='assert' && (a = expression_rule(p)) // expression && @@ -3590,7 +3606,7 @@ import_name_rule(Parser *p) Token * _keyword; asdl_alias_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='import' + (_keyword = _PyPegen_expect_token(p, 647)) // token='import' && (a = dotted_as_names_rule(p)) // dotted_as_names ) @@ -3659,13 +3675,13 @@ import_from_rule(Parser *p) expr_ty b; asdl_alias_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword = _PyPegen_expect_token(p, 646)) // token='from' && (a = _loop0_17_rule(p)) // (('.' | '...'))* && (b = dotted_name_rule(p)) // dotted_name && - (_keyword_1 = _PyPegen_expect_token(p, 643)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' && (c = import_from_targets_rule(p)) // import_from_targets ) @@ -3703,11 +3719,11 @@ import_from_rule(Parser *p) asdl_seq * a; asdl_alias_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword = _PyPegen_expect_token(p, 646)) // token='from' && (a = _loop1_18_rule(p)) // (('.' | '...'))+ && - (_keyword_1 = _PyPegen_expect_token(p, 643)) // token='import' + (_keyword_1 = _PyPegen_expect_token(p, 647)) // token='import' && (b = import_from_targets_rule(p)) // import_from_targets ) @@ -4494,7 +4510,7 @@ class_def_raw_rule(Parser *p) asdl_stmt_seq* c; void *t; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='class' + (_keyword = _PyPegen_expect_token(p, 714)) // token='class' && (a = _PyPegen_name_token(p)) // NAME && @@ -4661,7 +4677,7 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 708)) // token='def' + (_keyword = _PyPegen_expect_token(p, 712)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -4722,9 +4738,9 @@ function_def_raw_rule(Parser *p) void *t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='def' + (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='def' && (n = _PyPegen_name_token(p)) // NAME && @@ -6062,7 +6078,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6107,7 +6123,7 @@ if_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (a = named_expression_rule(p)) // named_expression && @@ -6202,7 +6218,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; stmt_ty c; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 700)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6247,7 +6263,7 @@ elif_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 700)) // token='elif' && (a = named_expression_rule(p)) // named_expression && @@ -6328,7 +6344,7 @@ else_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword = _PyPegen_expect_token(p, 699)) // token='else' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -6407,7 +6423,7 @@ while_stmt_rule(Parser *p) asdl_stmt_seq* b; void *c; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='while' + (_keyword = _PyPegen_expect_token(p, 702)) // token='while' && (a = named_expression_rule(p)) // named_expression && @@ -6507,11 +6523,11 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='in' && (_cut_var = 1) && @@ -6569,13 +6585,13 @@ for_stmt_rule(Parser *p) expr_ty t; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 707)) // token='for' && (t = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 708)) // token='in' && (_cut_var = 1) && @@ -6704,7 +6720,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword = _PyPegen_expect_token(p, 660)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6755,7 +6771,7 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword = _PyPegen_expect_token(p, 660)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6804,9 +6820,9 @@ with_stmt_rule(Parser *p) asdl_withitem_seq* a; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 660)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && @@ -6856,9 +6872,9 @@ with_stmt_rule(Parser *p) asdl_stmt_seq* b; void *tc; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword_1 = _PyPegen_expect_token(p, 660)) // token='with' && (a = (asdl_withitem_seq*)_gather_34_rule(p)) // ','.with_item+ && @@ -6944,7 +6960,7 @@ with_item_rule(Parser *p) if ( (e = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (t = star_target_rule(p)) // star_target && @@ -7069,7 +7085,7 @@ try_stmt_rule(Parser *p) asdl_stmt_seq* b; asdl_stmt_seq* f; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7113,7 +7129,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7161,7 +7177,7 @@ try_stmt_rule(Parser *p) asdl_excepthandler_seq* ex; void *f; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -7260,7 +7276,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (e = expression_rule(p)) // expression && @@ -7304,11 +7320,11 @@ except_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7350,7 +7366,7 @@ except_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (e = expressions_rule(p)) // expressions && @@ -7391,7 +7407,7 @@ except_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* b; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -7503,7 +7519,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7550,13 +7566,13 @@ except_star_block_rule(Parser *p) expr_ty e; expr_ty t; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (e = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (t = _PyPegen_name_token(p)) // NAME && @@ -7599,7 +7615,7 @@ except_star_block_rule(Parser *p) asdl_stmt_seq* b; expr_ty e; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -7699,7 +7715,7 @@ finally_block_rule(Parser *p) Token * _literal; asdl_stmt_seq* a; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 686)) // token='finally' && (_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':' && @@ -8007,7 +8023,7 @@ guard_rule(Parser *p) Token * _keyword; expr_ty guard; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (guard = named_expression_rule(p)) // named_expression ) @@ -8202,7 +8218,7 @@ as_pattern_rule(Parser *p) if ( (pattern = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (target = pattern_capture_target_rule(p)) // pattern_capture_target ) @@ -8636,7 +8652,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 624)) // token='None' + (_keyword = _PyPegen_expect_token(p, 628)) // token='None' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -8669,7 +8685,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='True' + (_keyword = _PyPegen_expect_token(p, 627)) // token='True' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -8702,7 +8718,7 @@ literal_pattern_rule(Parser *p) D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 625)) // token='False' + (_keyword = _PyPegen_expect_token(p, 629)) // token='False' ) { D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -8830,7 +8846,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 624)) // token='None' + (_keyword = _PyPegen_expect_token(p, 628)) // token='None' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -8863,7 +8879,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='True' + (_keyword = _PyPegen_expect_token(p, 627)) // token='True' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -8896,7 +8912,7 @@ literal_expr_rule(Parser *p) D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 625)) // token='False' + (_keyword = _PyPegen_expect_token(p, 629)) // token='False' ) { D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -11437,9 +11453,10 @@ expressions_rule(Parser *p) } // expression: +// | invalid_if_expression // | invalid_expression // | invalid_legacy_expression -// | disjunction 'if' disjunction 'else' expression +// | if_expression // | disjunction // | lambdef static expr_ty @@ -11458,15 +11475,25 @@ expression_rule(Parser *p) return _res; } int _mark = p->mark; - if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { - p->error_indicator = 1; - p->level--; - return NULL; + if (p->call_invalid_rules) { // invalid_if_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_if_expression")); + void *invalid_if_expression_var; + if ( + (invalid_if_expression_var = invalid_if_expression_rule(p)) // invalid_if_expression + ) + { + D(fprintf(stderr, "%*c+ expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_if_expression")); + _res = invalid_if_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s expression[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_if_expression")); } - int _start_lineno = p->tokens[_mark]->lineno; - UNUSED(_start_lineno); // Only used by EXTRA macro - int _start_col_offset = p->tokens[_mark]->col_offset; - UNUSED(_start_col_offset); // Only used by EXTRA macro if (p->call_invalid_rules) { // invalid_expression if (p->error_indicator) { p->level--; @@ -11505,50 +11532,24 @@ expression_rule(Parser *p) D(fprintf(stderr, "%*c%s expression[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_legacy_expression")); } - { // disjunction 'if' disjunction 'else' expression + { // if_expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); - Token * _keyword; - Token * _keyword_1; - expr_ty a; - expr_ty b; - expr_ty c; + D(fprintf(stderr, "%*c> expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "if_expression")); + expr_ty if_expression_var; if ( - (a = disjunction_rule(p)) // disjunction - && - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' - && - (b = disjunction_rule(p)) // disjunction - && - (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' - && - (c = expression_rule(p)) // expression + (if_expression_var = if_expression_rule(p)) // if_expression ) { - D(fprintf(stderr, "%*c+ expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); - Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); - if (_token == NULL) { - p->level--; - return NULL; - } - int _end_lineno = _token->end_lineno; - UNUSED(_end_lineno); // Only used by EXTRA macro - int _end_col_offset = _token->end_col_offset; - UNUSED(_end_col_offset); // Only used by EXTRA macro - _res = _PyAST_IfExp ( b , a , c , EXTRA ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } + D(fprintf(stderr, "%*c+ expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "if_expression")); + _res = if_expression_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s expression[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "if_expression")); } { // disjunction if (p->error_indicator) { @@ -11595,6 +11596,79 @@ expression_rule(Parser *p) return _res; } +// if_expression: disjunction 'if' disjunction 'else' expression +static expr_ty +if_expression_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) { + p->error_indicator = 1; + p->level--; + return NULL; + } + int _start_lineno = p->tokens[_mark]->lineno; + UNUSED(_start_lineno); // Only used by EXTRA macro + int _start_col_offset = p->tokens[_mark]->col_offset; + UNUSED(_start_col_offset); // Only used by EXTRA macro + { // disjunction 'if' disjunction 'else' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> if_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); + Token * _keyword; + Token * _keyword_1; + expr_ty a; + expr_ty b; + expr_ty c; + if ( + (a = disjunction_rule(p)) // disjunction + && + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' + && + (b = disjunction_rule(p)) // disjunction + && + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' + && + (c = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ if_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + p->level--; + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_IfExp ( b , a , c , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s if_expression[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction 'else' expression")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // yield_expr: 'yield' 'from' expression | 'yield' star_expressions? static expr_ty yield_expr_rule(Parser *p) @@ -11629,7 +11703,7 @@ yield_expr_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 588)) // token='yield' && - (_keyword_1 = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword_1 = _PyPegen_expect_token(p, 646)) // token='from' && (a = expression_rule(p)) // expression ) @@ -11959,6 +12033,53 @@ star_named_expressions_rule(Parser *p) return _res; } +// star_named_expressions_sequence: ','.star_named_expression_sequence+ ','? +static asdl_expr_seq* +star_named_expressions_sequence_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_expr_seq* _res = NULL; + int _mark = p->mark; + { // ','.star_named_expression_sequence+ ','? + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> star_named_expressions_sequence[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.star_named_expression_sequence+ ','?")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + asdl_expr_seq* a; + if ( + (a = (asdl_expr_seq*)_gather_60_rule(p)) // ','.star_named_expression_sequence+ + && + (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? + ) + { + D(fprintf(stderr, "%*c+ star_named_expressions_sequence[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.star_named_expression_sequence+ ','?")); + _res = a; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_named_expressions_sequence[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.star_named_expression_sequence+ ','?")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // star_named_expression: '*' bitwise_or | named_expression static expr_ty star_named_expression_rule(Parser *p) @@ -12042,6 +12163,65 @@ star_named_expression_rule(Parser *p) return _res; } +// star_named_expression_sequence: +// | invalid_starred_expression_unpacking_sequence +// | star_named_expression +static expr_ty +star_named_expression_sequence_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + expr_ty _res = NULL; + int _mark = p->mark; + if (p->call_invalid_rules) { // invalid_starred_expression_unpacking_sequence + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> star_named_expression_sequence[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_starred_expression_unpacking_sequence")); + void *invalid_starred_expression_unpacking_sequence_var; + if ( + (invalid_starred_expression_unpacking_sequence_var = invalid_starred_expression_unpacking_sequence_rule(p)) // invalid_starred_expression_unpacking_sequence + ) + { + D(fprintf(stderr, "%*c+ star_named_expression_sequence[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_starred_expression_unpacking_sequence")); + _res = invalid_starred_expression_unpacking_sequence_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_named_expression_sequence[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_starred_expression_unpacking_sequence")); + } + { // star_named_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> star_named_expression_sequence[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression")); + expr_ty star_named_expression_var; + if ( + (star_named_expression_var = star_named_expression_rule(p)) // star_named_expression + ) + { + D(fprintf(stderr, "%*c+ star_named_expression_sequence[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression")); + _res = star_named_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s star_named_expression_sequence[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // assignment_expression: NAME ':=' ~ expression static expr_ty assignment_expression_rule(Parser *p) @@ -12231,7 +12411,7 @@ disjunction_rule(Parser *p) if ( (a = conjunction_rule(p)) // conjunction && - (b = _loop1_59_rule(p)) // (('or' conjunction))+ + (b = _loop1_61_rule(p)) // (('or' conjunction))+ ) { D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+")); @@ -12319,7 +12499,7 @@ conjunction_rule(Parser *p) if ( (a = inversion_rule(p)) // inversion && - (b = _loop1_60_rule(p)) // (('and' inversion))+ + (b = _loop1_62_rule(p)) // (('and' inversion))+ ) { D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+")); @@ -12405,7 +12585,7 @@ inversion_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 712)) // token='not' + (_keyword = _PyPegen_expect_token(p, 716)) // token='not' && (a = inversion_rule(p)) // inversion ) @@ -12491,7 +12671,7 @@ comparison_rule(Parser *p) if ( (a = bitwise_or_rule(p)) // bitwise_or && - (b = _loop1_61_rule(p)) // compare_op_bitwise_or_pair+ + (b = _loop1_63_rule(p)) // compare_op_bitwise_or_pair+ ) { D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+")); @@ -12825,10 +13005,10 @@ noteq_bitwise_or_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or")); - void *_tmp_62_var; + void *_tmp_64_var; expr_ty a; if ( - (_tmp_62_var = _tmp_62_rule(p)) // '!=' + (_tmp_64_var = _tmp_64_rule(p)) // '!=' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13059,9 +13239,9 @@ notin_bitwise_or_rule(Parser *p) Token * _keyword_1; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 712)) // token='not' + (_keyword = _PyPegen_expect_token(p, 716)) // token='not' && - (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13107,7 +13287,7 @@ in_bitwise_or_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword = _PyPegen_expect_token(p, 708)) // token='in' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -13156,7 +13336,7 @@ isnot_bitwise_or_rule(Parser *p) if ( (_keyword = _PyPegen_expect_token(p, 597)) // token='is' && - (_keyword_1 = _PyPegen_expect_token(p, 712)) // token='not' + (_keyword_1 = _PyPegen_expect_token(p, 716)) // token='not' && (a = bitwise_or_rule(p)) // bitwise_or ) @@ -14876,7 +15056,7 @@ slices_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_64_rule(p)) // ','.(slice | starred_expression)+ + (a = (asdl_expr_seq*)_gather_66_rule(p)) // ','.(slice | starred_expression)+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -14948,7 +15128,7 @@ slice_rule(Parser *p) && (b = expression_rule(p), !p->error_indicator) // expression? && - (c = _tmp_65_rule(p), !p->error_indicator) // [':' expression?] + (c = _tmp_67_rule(p), !p->error_indicator) // [':' expression?] ) { D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]")); @@ -15010,9 +15190,9 @@ slice_rule(Parser *p) // | 'None' // | &(STRING | FSTRING_START | TSTRING_START) strings // | NUMBER -// | &'(' (tuple | group | genexp) -// | &'[' (list | listcomp) -// | &'{' (dict | set | dictcomp | setcomp) +// | &'(' (genexp | tuple | group) +// | &'[' (listcomp | list) +// | &'{' (dictcomp | setcomp | dict | set) // | '...' static expr_ty atom_rule(Parser *p) @@ -15062,7 +15242,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='True' + (_keyword = _PyPegen_expect_token(p, 627)) // token='True' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); @@ -15095,7 +15275,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 625)) // token='False' + (_keyword = _PyPegen_expect_token(p, 629)) // token='False' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); @@ -15128,7 +15308,7 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 624)) // token='None' + (_keyword = _PyPegen_expect_token(p, 628)) // token='None' ) { D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); @@ -15193,68 +15373,68 @@ atom_rule(Parser *p) D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NUMBER")); } - { // &'(' (tuple | group | genexp) + { // &'(' (genexp | tuple | group) if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - void *_tmp_66_var; + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (genexp | tuple | group)")); + void *_tmp_68_var; if ( _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='(' && - (_tmp_66_var = _tmp_66_rule(p)) // tuple | group | genexp + (_tmp_68_var = _tmp_68_rule(p)) // genexp | tuple | group ) { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)")); - _res = _tmp_66_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'(' (tuple | group | genexp)")); - } - { // &'[' (list | listcomp) - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - void *_tmp_67_var; - if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' - && - (_tmp_67_var = _tmp_67_rule(p)) // list | listcomp - ) - { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)")); - _res = _tmp_67_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'[' (list | listcomp)")); - } - { // &'{' (dict | set | dictcomp | setcomp) - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); - void *_tmp_68_var; - if ( - _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' - && - (_tmp_68_var = _tmp_68_rule(p)) // dict | set | dictcomp | setcomp - ) - { - D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (genexp | tuple | group)")); _res = _tmp_68_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'(' (genexp | tuple | group)")); + } + { // &'[' (listcomp | list) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (listcomp | list)")); + void *_tmp_69_var; + if ( + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='[' + && + (_tmp_69_var = _tmp_69_rule(p)) // listcomp | list + ) + { + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (listcomp | list)")); + _res = _tmp_69_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'[' (listcomp | list)")); + } + { // &'{' (dictcomp | setcomp | dict | set) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dictcomp | setcomp | dict | set)")); + void *_tmp_70_var; + if ( + _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{' + && + (_tmp_70_var = _tmp_70_rule(p)) // dictcomp | setcomp | dict | set + ) + { + D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dictcomp | setcomp | dict | set)")); + _res = _tmp_70_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&'{' (dictcomp | setcomp | dict | set)")); } { // '...' if (p->error_indicator) { @@ -15320,7 +15500,7 @@ group_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_69_rule(p)) // yield_expr | named_expression + (a = _tmp_71_rule(p)) // yield_expr | named_expression && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) @@ -15521,9 +15701,9 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default && - (b = (asdl_arg_seq*)_loop0_70_rule(p)) // lambda_param_no_default* + (b = (asdl_arg_seq*)_loop0_72_rule(p)) // lambda_param_no_default* && - (c = _loop0_71_rule(p)) // lambda_param_with_default* + (c = _loop0_73_rule(p)) // lambda_param_with_default* && (d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15553,7 +15733,7 @@ lambda_parameters_rule(Parser *p) if ( (a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default && - (b = _loop0_71_rule(p)) // lambda_param_with_default* + (b = _loop0_73_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15581,9 +15761,9 @@ lambda_parameters_rule(Parser *p) asdl_seq * b; void *c; if ( - (a = (asdl_arg_seq*)_loop1_72_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ && - (b = _loop0_71_rule(p)) // lambda_param_with_default* + (b = _loop0_73_rule(p)) // lambda_param_with_default* && (c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15610,7 +15790,7 @@ lambda_parameters_rule(Parser *p) asdl_seq * a; void *b; if ( - (a = _loop1_73_rule(p)) // lambda_param_with_default+ + (a = _loop1_75_rule(p)) // lambda_param_with_default+ && (b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc? ) @@ -15683,7 +15863,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal_1; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_72_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15712,7 +15892,7 @@ lambda_slash_no_default_rule(Parser *p) Token * _literal; asdl_arg_seq* a; if ( - (a = (asdl_arg_seq*)_loop1_72_rule(p)) // lambda_param_no_default+ + (a = (asdl_arg_seq*)_loop1_74_rule(p)) // lambda_param_no_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15764,9 +15944,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_70_rule(p)) // lambda_param_no_default* + (a = _loop0_72_rule(p)) // lambda_param_no_default* && - (b = _loop1_73_rule(p)) // lambda_param_with_default+ + (b = _loop1_75_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15796,9 +15976,9 @@ lambda_slash_with_default_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _loop0_70_rule(p)) // lambda_param_no_default* + (a = _loop0_72_rule(p)) // lambda_param_no_default* && - (b = _loop1_73_rule(p)) // lambda_param_with_default+ + (b = _loop1_75_rule(p)) // lambda_param_with_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -15875,7 +16055,7 @@ lambda_star_etc_rule(Parser *p) && (a = lambda_param_no_default_rule(p)) // lambda_param_no_default && - (b = _loop0_74_rule(p)) // lambda_param_maybe_default* + (b = _loop0_76_rule(p)) // lambda_param_maybe_default* && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -15908,7 +16088,7 @@ lambda_star_etc_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _loop1_75_rule(p)) // lambda_param_maybe_default+ + (b = _loop1_77_rule(p)) // lambda_param_maybe_default+ && (c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds? ) @@ -16548,7 +16728,7 @@ fstring_full_format_spec_rule(Parser *p) if ( (colon = _PyPegen_expect_token(p, 11)) // token=':' && - (spec = _loop0_76_rule(p)) // fstring_format_spec* + (spec = _loop0_78_rule(p)) // fstring_format_spec* ) { D(fprintf(stderr, "%*c+ fstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*")); @@ -16666,7 +16846,7 @@ fstring_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START' && - (b = _loop0_77_rule(p)) // fstring_middle* + (b = _loop0_79_rule(p)) // fstring_middle* && (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END' ) @@ -16882,7 +17062,7 @@ tstring_full_format_spec_rule(Parser *p) if ( (colon = _PyPegen_expect_token(p, 11)) // token=':' && - (spec = _loop0_78_rule(p)) // tstring_format_spec* + (spec = _loop0_80_rule(p)) // tstring_format_spec* ) { D(fprintf(stderr, "%*c+ tstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' tstring_format_spec*")); @@ -17101,7 +17281,7 @@ tstring_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, TSTRING_START)) // token='TSTRING_START' && - (b = _loop0_79_rule(p)) // tstring_middle* + (b = _loop0_81_rule(p)) // tstring_middle* && (c = _PyPegen_expect_token(p, TSTRING_END)) // token='TSTRING_END' ) @@ -17222,7 +17402,7 @@ strings_rule(Parser *p) D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_80_rule(p)) // ((fstring | string))+ + (a = (asdl_expr_seq*)_loop1_82_rule(p)) // ((fstring | string))+ ) { D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+")); @@ -17255,7 +17435,7 @@ strings_rule(Parser *p) D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_loop1_81_rule(p)) // tstring+ + (a = (asdl_expr_seq*)_loop1_83_rule(p)) // tstring+ ) { D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tstring+")); @@ -17287,7 +17467,7 @@ strings_rule(Parser *p) return _res; } -// list: '[' star_named_expressions? ']' +// list: '[' star_named_expressions_sequence? ']' static expr_ty list_rule(Parser *p) { @@ -17309,24 +17489,24 @@ list_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '[' star_named_expressions? ']' + { // '[' star_named_expressions_sequence? ']' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> list[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_named_expressions? ']'")); + D(fprintf(stderr, "%*c> list[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_named_expressions_sequence? ']'")); Token * _literal; Token * _literal_1; void *a; if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' && - (a = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? + (a = star_named_expressions_sequence_rule(p), !p->error_indicator) // star_named_expressions_sequence? && (_literal_1 = _PyPegen_expect_token(p, 10)) // token=']' ) { - D(fprintf(stderr, "%*c+ list[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_named_expressions? ']'")); + D(fprintf(stderr, "%*c+ list[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_named_expressions_sequence? ']'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -17346,7 +17526,7 @@ list_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s list[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_named_expressions? ']'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_named_expressions_sequence? ']'")); } _res = NULL; done: @@ -17354,7 +17534,7 @@ list_rule(Parser *p) return _res; } -// tuple: '(' [star_named_expression ',' star_named_expressions?] ')' +// tuple: '(' [star_named_expression_sequence ',' star_named_expressions_sequence?] ')' static expr_ty tuple_rule(Parser *p) { @@ -17376,24 +17556,24 @@ tuple_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '(' [star_named_expression ',' star_named_expressions?] ')' + { // '(' [star_named_expression_sequence ',' star_named_expressions_sequence?] ')' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> tuple[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' [star_named_expression ',' star_named_expressions?] ')'")); + D(fprintf(stderr, "%*c> tuple[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' [star_named_expression_sequence ',' star_named_expressions_sequence?] ')'")); Token * _literal; Token * _literal_1; void *a; if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_82_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?] + (a = _tmp_84_rule(p), !p->error_indicator) // [star_named_expression_sequence ',' star_named_expressions_sequence?] && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ tuple[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' [star_named_expression ',' star_named_expressions?] ')'")); + D(fprintf(stderr, "%*c+ tuple[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' [star_named_expression_sequence ',' star_named_expressions_sequence?] ')'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -17413,7 +17593,7 @@ tuple_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s tuple[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' [star_named_expression ',' star_named_expressions?] ')'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' [star_named_expression_sequence ',' star_named_expressions_sequence?] ')'")); } _res = NULL; done: @@ -17421,7 +17601,7 @@ tuple_rule(Parser *p) return _res; } -// set: '{' star_named_expressions '}' +// set: '{' star_named_expressions_sequence '}' static expr_ty set_rule(Parser *p) { @@ -17443,24 +17623,24 @@ set_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' star_named_expressions '}' + { // '{' star_named_expressions_sequence '}' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> set[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions '}'")); + D(fprintf(stderr, "%*c> set[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions_sequence '}'")); Token * _literal; Token * _literal_1; asdl_expr_seq* a; if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = star_named_expressions_rule(p)) // star_named_expressions + (a = star_named_expressions_sequence_rule(p)) // star_named_expressions_sequence && (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ set[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions '}'")); + D(fprintf(stderr, "%*c+ set[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' star_named_expressions_sequence '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -17480,7 +17660,7 @@ set_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s set[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' star_named_expressions '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' star_named_expressions_sequence '}'")); } _res = NULL; done: @@ -17603,7 +17783,7 @@ double_starred_kvpairs_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_seq * a; if ( - (a = _gather_84_rule(p)) // ','.double_starred_kvpair+ + (a = _gather_86_rule(p)) // ','.double_starred_kvpair+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -17762,7 +17942,7 @@ for_if_clauses_rule(Parser *p) D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); asdl_comprehension_seq* a; if ( - (a = (asdl_comprehension_seq*)_loop1_85_rule(p)) // for_if_clause+ + (a = (asdl_comprehension_seq*)_loop1_87_rule(p)) // for_if_clause+ ) { D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+")); @@ -17815,19 +17995,19 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' && - (_keyword_1 = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword_1 = _PyPegen_expect_token(p, 707)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_2 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_2 = _PyPegen_expect_token(p, 708)) // token='in' && (_cut_var = 1) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_86_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_88_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async' 'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -17860,17 +18040,17 @@ for_if_clause_rule(Parser *p) expr_ty b; asdl_expr_seq* c; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' && (a = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='in' && (_cut_var = 1) && (b = disjunction_rule(p)) // disjunction && - (c = (asdl_expr_seq*)_loop0_86_rule(p)) // (('if' disjunction))* + (c = (asdl_expr_seq*)_loop0_88_rule(p)) // (('if' disjunction))* ) { D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*")); @@ -17934,7 +18114,7 @@ for_if_clause_rule(Parser *p) return _res; } -// listcomp: '[' named_expression for_if_clauses ']' | invalid_comprehension +// listcomp: '[' star_named_expression for_if_clauses ']' | invalid_comprehension static expr_ty listcomp_rule(Parser *p) { @@ -17956,12 +18136,12 @@ listcomp_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '[' named_expression for_if_clauses ']' + { // '[' star_named_expression for_if_clauses ']' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> listcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' named_expression for_if_clauses ']'")); + D(fprintf(stderr, "%*c> listcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' star_named_expression for_if_clauses ']'")); Token * _literal; Token * _literal_1; expr_ty a; @@ -17969,14 +18149,14 @@ listcomp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 9)) // token='[' && - (a = named_expression_rule(p)) // named_expression + (a = star_named_expression_rule(p)) // star_named_expression && (b = for_if_clauses_rule(p)) // for_if_clauses && (_literal_1 = _PyPegen_expect_token(p, 10)) // token=']' ) { - D(fprintf(stderr, "%*c+ listcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' named_expression for_if_clauses ']'")); + D(fprintf(stderr, "%*c+ listcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' star_named_expression for_if_clauses ']'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -17996,7 +18176,7 @@ listcomp_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s listcomp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' named_expression for_if_clauses ']'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' star_named_expression for_if_clauses ']'")); } if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { @@ -18023,7 +18203,7 @@ listcomp_rule(Parser *p) return _res; } -// setcomp: '{' named_expression for_if_clauses '}' | invalid_comprehension +// setcomp: '{' star_named_expression for_if_clauses '}' | invalid_comprehension static expr_ty setcomp_rule(Parser *p) { @@ -18045,12 +18225,12 @@ setcomp_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '{' named_expression for_if_clauses '}' + { // '{' star_named_expression for_if_clauses '}' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> setcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' named_expression for_if_clauses '}'")); + D(fprintf(stderr, "%*c> setcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' star_named_expression for_if_clauses '}'")); Token * _literal; Token * _literal_1; expr_ty a; @@ -18058,14 +18238,14 @@ setcomp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (a = named_expression_rule(p)) // named_expression + (a = star_named_expression_rule(p)) // star_named_expression && (b = for_if_clauses_rule(p)) // for_if_clauses && (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ setcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' named_expression for_if_clauses '}'")); + D(fprintf(stderr, "%*c+ setcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' star_named_expression for_if_clauses '}'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -18085,7 +18265,7 @@ setcomp_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s setcomp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' named_expression for_if_clauses '}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' star_named_expression for_if_clauses '}'")); } if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { @@ -18113,7 +18293,7 @@ setcomp_rule(Parser *p) } // genexp: -// | '(' (assignment_expression | expression !':=') for_if_clauses ')' +// | '(' (assignment_expression | expression !':=' | starred_expression) for_if_clauses ')' // | invalid_comprehension static expr_ty genexp_rule(Parser *p) @@ -18136,12 +18316,12 @@ genexp_rule(Parser *p) UNUSED(_start_lineno); // Only used by EXTRA macro int _start_col_offset = p->tokens[_mark]->col_offset; UNUSED(_start_col_offset); // Only used by EXTRA macro - { // '(' (assignment_expression | expression !':=') for_if_clauses ')' + { // '(' (assignment_expression | expression !':=' | starred_expression) for_if_clauses ')' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> genexp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' (assignment_expression | expression !':=') for_if_clauses ')'")); + D(fprintf(stderr, "%*c> genexp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' (assignment_expression | expression !':=' | starred_expression) for_if_clauses ')'")); Token * _literal; Token * _literal_1; void *a; @@ -18149,14 +18329,14 @@ genexp_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (a = _tmp_87_rule(p)) // assignment_expression | expression !':=' + (a = _tmp_89_rule(p)) // assignment_expression | expression !':=' | starred_expression && (b = for_if_clauses_rule(p)) // for_if_clauses && (_literal_1 = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ genexp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' (assignment_expression | expression !':=') for_if_clauses ')'")); + D(fprintf(stderr, "%*c+ genexp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' (assignment_expression | expression !':=' | starred_expression) for_if_clauses ')'")); Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); if (_token == NULL) { p->level--; @@ -18176,7 +18356,7 @@ genexp_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s genexp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' (assignment_expression | expression !':=') for_if_clauses ')'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' (assignment_expression | expression !':=' | starred_expression) for_if_clauses ')'")); } if (p->call_invalid_rules) { // invalid_comprehension if (p->error_indicator) { @@ -18203,7 +18383,7 @@ genexp_rule(Parser *p) return _res; } -// dictcomp: '{' kvpair for_if_clauses '}' | invalid_dict_comprehension +// dictcomp: '{' kvpair for_if_clauses '}' | '{' '**' expression for_if_clauses '}' static expr_ty dictcomp_rule(Parser *p) { @@ -18267,24 +18447,50 @@ dictcomp_rule(Parser *p) D(fprintf(stderr, "%*c%s dictcomp[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' kvpair for_if_clauses '}'")); } - if (p->call_invalid_rules) { // invalid_dict_comprehension + { // '{' '**' expression for_if_clauses '}' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> dictcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_dict_comprehension")); - void *invalid_dict_comprehension_var; + D(fprintf(stderr, "%*c> dictcomp[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '**' expression for_if_clauses '}'")); + Token * _literal; + Token * _literal_1; + Token * _literal_2; + expr_ty a; + asdl_comprehension_seq* b; if ( - (invalid_dict_comprehension_var = invalid_dict_comprehension_rule(p)) // invalid_dict_comprehension + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + && + (_literal_1 = _PyPegen_expect_token(p, 35)) // token='**' + && + (a = expression_rule(p)) // expression + && + (b = for_if_clauses_rule(p)) // for_if_clauses + && + (_literal_2 = _PyPegen_expect_token(p, 26)) // token='}' ) { - D(fprintf(stderr, "%*c+ dictcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_dict_comprehension")); - _res = invalid_dict_comprehension_var; + D(fprintf(stderr, "%*c+ dictcomp[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '**' expression for_if_clauses '}'")); + Token *_token = _PyPegen_get_last_nonnwhitespace_token(p); + if (_token == NULL) { + p->level--; + return NULL; + } + int _end_lineno = _token->end_lineno; + UNUSED(_end_lineno); // Only used by EXTRA macro + int _end_col_offset = _token->end_col_offset; + UNUSED(_end_col_offset); // Only used by EXTRA macro + _res = _PyAST_DictComp ( a , NULL , b , EXTRA ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s dictcomp[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_dict_comprehension")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '**' expression for_if_clauses '}'")); } _res = NULL; done: @@ -18398,9 +18604,9 @@ args_rule(Parser *p) asdl_expr_seq* a; void *b; if ( - (a = (asdl_expr_seq*)_gather_89_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (a = (asdl_expr_seq*)_gather_91_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && - (b = _tmp_90_rule(p), !p->error_indicator) // [',' kwargs] + (b = _tmp_92_rule(p), !p->error_indicator) // [',' kwargs] ) { D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs]")); @@ -18490,11 +18696,11 @@ kwargs_rule(Parser *p) asdl_seq * a; asdl_seq * b; if ( - (a = _gather_92_rule(p)) // ','.kwarg_or_starred+ + (a = _gather_94_rule(p)) // ','.kwarg_or_starred+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (b = _gather_94_rule(p)) // ','.kwarg_or_double_starred+ + (b = _gather_96_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+")); @@ -18516,13 +18722,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - asdl_seq * _gather_92_var; + asdl_seq * _gather_94_var; if ( - (_gather_92_var = _gather_92_rule(p)) // ','.kwarg_or_starred+ + (_gather_94_var = _gather_94_rule(p)) // ','.kwarg_or_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+")); - _res = _gather_92_var; + _res = _gather_94_var; goto done; } p->mark = _mark; @@ -18535,13 +18741,13 @@ kwargs_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - asdl_seq * _gather_94_var; + asdl_seq * _gather_96_var; if ( - (_gather_94_var = _gather_94_rule(p)) // ','.kwarg_or_double_starred+ + (_gather_96_var = _gather_96_rule(p)) // ','.kwarg_or_double_starred+ ) { D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+")); - _res = _gather_94_var; + _res = _gather_96_var; goto done; } p->mark = _mark; @@ -18952,7 +19158,7 @@ star_targets_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop0_95_rule(p)) // ((',' star_target))* + (b = _loop0_97_rule(p)) // ((',' star_target))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19008,7 +19214,7 @@ star_targets_list_seq_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_97_rule(p)) // ','.star_target+ + (a = (asdl_expr_seq*)_gather_99_rule(p)) // ','.star_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19058,7 +19264,7 @@ star_targets_tuple_seq_rule(Parser *p) if ( (a = star_target_rule(p)) // star_target && - (b = _loop1_98_rule(p)) // ((',' star_target))+ + (b = _loop1_100_rule(p)) // ((',' star_target))+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -19146,7 +19352,7 @@ star_target_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (a = _tmp_99_rule(p)) // !'*' star_target + (a = _tmp_101_rule(p)) // !'*' star_target ) { D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)")); @@ -20069,7 +20275,7 @@ del_targets_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_101_rule(p)) // ','.del_target+ + (a = (asdl_expr_seq*)_gather_103_rule(p)) // ','.del_target+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) @@ -20427,7 +20633,7 @@ type_expressions_rule(Parser *p) expr_ty b; expr_ty c; if ( - (a = _gather_103_rule(p)) // ','.expression+ + (a = _gather_105_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -20466,7 +20672,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_103_rule(p)) // ','.expression+ + (a = _gather_105_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -20499,7 +20705,7 @@ type_expressions_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _gather_103_rule(p)) // ','.expression+ + (a = _gather_105_rule(p)) // ','.expression+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && @@ -20619,7 +20825,7 @@ type_expressions_rule(Parser *p) D(fprintf(stderr, "%*c> type_expressions[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.expression+")); asdl_expr_seq* a; if ( - (a = (asdl_expr_seq*)_gather_103_rule(p)) // ','.expression+ + (a = (asdl_expr_seq*)_gather_105_rule(p)) // ','.expression+ ) { D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+")); @@ -20670,7 +20876,7 @@ func_type_comment_rule(Parser *p) && (t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT' && - _PyPegen_lookahead(1, _tmp_104_rule, p) + _PyPegen_lookahead(1, _tmp_106_rule, p) ) { D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)")); @@ -20756,15 +20962,15 @@ invalid_arguments_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_arguments[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' ','.(starred_expression !'=')+")); - asdl_seq * _gather_107_var; - void *_tmp_105_var; + asdl_seq * _gather_109_var; + void *_tmp_107_var; Token * a; if ( - (_tmp_105_var = _tmp_105_rule(p)) // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs + (_tmp_107_var = _tmp_107_rule(p)) // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs && (a = _PyPegen_expect_token(p, 12)) // token=',' && - (_gather_107_var = _gather_107_rule(p)) // ','.(starred_expression !'=')+ + (_gather_109_var = _gather_109_rule(p)) // ','.(starred_expression !'=')+ ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) | kwargs) ',' ','.(starred_expression !'=')+")); @@ -20798,7 +21004,7 @@ invalid_arguments_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_opt_var = _tmp_108_rule(p), !p->error_indicator) // [args | expression for_if_clauses] + (_opt_var = _tmp_110_rule(p), !p->error_indicator) // [args | expression for_if_clauses] ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]")); @@ -20858,13 +21064,13 @@ invalid_arguments_rule(Parser *p) expr_ty a; Token * b; if ( - (_opt_var = _tmp_109_rule(p), !p->error_indicator) // [(args ',')] + (_opt_var = _tmp_111_rule(p), !p->error_indicator) // [(args ',')] && (a = _PyPegen_name_token(p)) // NAME && (b = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_110_rule, p) + _PyPegen_lookahead(1, _tmp_112_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')")); @@ -21002,7 +21208,7 @@ invalid_kwarg_rule(Parser *p) Token* a; Token * b; if ( - (a = (Token*)_tmp_111_rule(p)) // 'True' | 'False' | 'None' + (a = (Token*)_tmp_113_rule(p)) // 'True' | 'False' | 'None' && (b = _PyPegen_expect_token(p, 22)) // token='=' ) @@ -21062,7 +21268,7 @@ invalid_kwarg_rule(Parser *p) expr_ty a; Token * b; if ( - _PyPegen_lookahead(0, _tmp_112_rule, p) + _PyPegen_lookahead(0, _tmp_114_rule, p) && (a = expression_rule(p)) // expression && @@ -21165,11 +21371,11 @@ expression_without_invalid_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' && (c = expression_rule(p)) // expression ) @@ -21410,7 +21616,7 @@ invalid_expression_rule(Parser *p) if ( (string_var = _PyPegen_string_token(p)) // STRING && - (a = _loop1_113_rule(p)) // ((!STRING expression_without_invalid))+ + (a = _loop1_115_rule(p)) // ((!STRING expression_without_invalid))+ && (string_var_1 = _PyPegen_string_token(p)) // STRING ) @@ -21437,7 +21643,7 @@ invalid_expression_rule(Parser *p) expr_ty a; expr_ty b; if ( - _PyPegen_lookahead(0, _tmp_114_rule, p) + _PyPegen_lookahead(0, _tmp_116_rule, p) && (a = disjunction_rule(p)) // disjunction && @@ -21469,11 +21675,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (b = disjunction_rule(p)) // disjunction && - _PyPegen_lookahead(0, _tmp_115_rule, p) + _PyPegen_lookahead(0, _tmp_117_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')")); @@ -21502,11 +21708,11 @@ invalid_expression_rule(Parser *p) if ( (a = disjunction_rule(p)) // disjunction && - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' && _PyPegen_lookahead_for_expr(0, expression_rule, p) ) @@ -21536,13 +21742,13 @@ invalid_expression_rule(Parser *p) expr_ty b; stmt_ty c; if ( - (a = (stmt_ty)_tmp_116_rule(p)) // pass_stmt | break_stmt | continue_stmt + (a = (stmt_ty)_tmp_118_rule(p)) // pass_stmt | break_stmt | continue_stmt && - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (b = disjunction_rule(p)) // disjunction && - (_keyword_1 = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' && (c = simple_stmt_rule(p)) // simple_stmt ) @@ -21632,6 +21838,99 @@ invalid_expression_rule(Parser *p) return _res; } +// invalid_if_expression: +// | disjunction 'if' disjunction 'else' '*' +// | disjunction 'if' disjunction 'else' '**' +static void * +invalid_if_expression_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // disjunction 'if' disjunction 'else' '*' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_if_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' '*'")); + Token * _keyword; + Token * _keyword_1; + Token * a; + expr_ty b; + expr_ty disjunction_var; + if ( + (disjunction_var = disjunction_rule(p)) // disjunction + && + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' + && + (b = disjunction_rule(p)) // disjunction + && + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' + && + (a = _PyPegen_expect_token(p, 16)) // token='*' + ) + { + D(fprintf(stderr, "%*c+ invalid_if_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' '*'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot unpack only part of a conditional expression" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_if_expression[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction 'else' '*'")); + } + { // disjunction 'if' disjunction 'else' '**' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_if_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' '**'")); + Token * _keyword; + Token * _keyword_1; + Token * a; + expr_ty b; + expr_ty disjunction_var; + if ( + (disjunction_var = disjunction_rule(p)) // disjunction + && + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' + && + (b = disjunction_rule(p)) // disjunction + && + (_keyword_1 = _PyPegen_expect_token(p, 699)) // token='else' + && + (a = _PyPegen_expect_token(p, 35)) // token='**' + ) + { + D(fprintf(stderr, "%*c+ invalid_if_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction 'else' '**'")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use dict unpacking on only part of a conditional expression" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_if_expression[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction 'else' '**'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_named_expression: // | expression ':=' expression // | NAME '=' bitwise_or !('=' | ':=') @@ -21698,7 +21997,7 @@ invalid_named_expression_rule(Parser *p) && (b = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_117_rule, p) + _PyPegen_lookahead(0, _tmp_119_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')")); @@ -21724,7 +22023,7 @@ invalid_named_expression_rule(Parser *p) Token * b; expr_ty bitwise_or_var; if ( - _PyPegen_lookahead(0, _tmp_118_rule, p) + _PyPegen_lookahead(0, _tmp_120_rule, p) && (a = bitwise_or_rule(p)) // bitwise_or && @@ -21732,7 +22031,7 @@ invalid_named_expression_rule(Parser *p) && (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - _PyPegen_lookahead(0, _tmp_117_rule, p) + _PyPegen_lookahead(0, _tmp_119_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')")); @@ -21812,7 +22111,7 @@ invalid_assignment_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_119_var; + asdl_seq * _loop0_121_var; expr_ty a; expr_ty expression_var; if ( @@ -21820,7 +22119,7 @@ invalid_assignment_rule(Parser *p) && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_loop0_119_var = _loop0_119_rule(p)) // star_named_expressions* + (_loop0_121_var = _loop0_121_rule(p)) // star_named_expressions* && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && @@ -21877,10 +22176,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='")); Token * _literal; - asdl_seq * _loop0_120_var; + asdl_seq * _loop0_122_var; expr_ty a; if ( - (_loop0_120_var = _loop0_120_rule(p)) // ((star_targets '='))* + (_loop0_122_var = _loop0_122_rule(p)) // ((star_targets '='))* && (a = star_expressions_rule(p)) // star_expressions && @@ -21907,10 +22206,10 @@ invalid_assignment_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='")); Token * _literal; - asdl_seq * _loop0_120_var; + asdl_seq * _loop0_122_var; expr_ty a; if ( - (_loop0_120_var = _loop0_120_rule(p)) // ((star_targets '='))* + (_loop0_122_var = _loop0_122_rule(p)) // ((star_targets '='))* && (a = yield_expr_rule(p)) // yield_expr && @@ -22075,9 +22374,9 @@ invalid_raise_stmt_rule(Parser *p) Token * a; Token * b; if ( - (a = _PyPegen_expect_token(p, 628)) // token='raise' + (a = _PyPegen_expect_token(p, 632)) // token='raise' && - (b = _PyPegen_expect_token(p, 642)) // token='from' + (b = _PyPegen_expect_token(p, 646)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' 'from'")); @@ -22103,11 +22402,11 @@ invalid_raise_stmt_rule(Parser *p) Token * a; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 628)) // token='raise' + (_keyword = _PyPegen_expect_token(p, 632)) // token='raise' && (expression_var = expression_rule(p)) // expression && - (a = _PyPegen_expect_token(p, 642)) // token='from' + (a = _PyPegen_expect_token(p, 646)) // token='from' ) { D(fprintf(stderr, "%*c+ invalid_raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression 'from'")); @@ -22151,7 +22450,7 @@ invalid_del_stmt_rule(Parser *p) Token * _keyword; expr_ty a; if ( - (_keyword = _PyPegen_expect_token(p, 630)) // token='del' + (_keyword = _PyPegen_expect_token(p, 634)) // token='del' && (a = star_expressions_rule(p)) // star_expressions ) @@ -22203,7 +22502,7 @@ invalid_assert_stmt_rule(Parser *p) expr_ty a; expr_ty b; if ( - (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 638)) // token='assert' && (a = expression_rule(p)) // expression && @@ -22238,7 +22537,7 @@ invalid_assert_stmt_rule(Parser *p) expr_ty b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 638)) // token='assert' && (expression_var = expression_rule(p)) // expression && @@ -22275,7 +22574,7 @@ invalid_assert_stmt_rule(Parser *p) expr_ty a; expr_ty b; if ( - (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 638)) // token='assert' && (a = expression_rule(p)) // expression && @@ -22310,7 +22609,7 @@ invalid_assert_stmt_rule(Parser *p) expr_ty b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 634)) // token='assert' + (_keyword = _PyPegen_expect_token(p, 638)) // token='assert' && (expression_var = expression_rule(p)) // expression && @@ -22388,7 +22687,8 @@ invalid_block_rule(Parser *p) } // invalid_comprehension: -// | ('[' | '(' | '{') starred_expression for_if_clauses +// | '[' '**' expression for_if_clauses +// | '(' '**' expression for_if_clauses // | ('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses // | ('[' | '{') star_named_expression ',' for_if_clauses static void * @@ -22403,25 +22703,28 @@ invalid_comprehension_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // ('[' | '(' | '{') starred_expression for_if_clauses + { // '[' '**' expression for_if_clauses if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - void *_tmp_121_var; - expr_ty a; + D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'[' '**' expression for_if_clauses")); + Token * _literal; + Token * a; + expr_ty b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_121_var = _tmp_121_rule(p)) // '[' | '(' | '{' + (_literal = _PyPegen_expect_token(p, 9)) // token='[' && - (a = starred_expression_rule(p)) // starred_expression + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (b = expression_rule(p)) // expression && (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ invalid_comprehension[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); - _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "iterable unpacking cannot be used in comprehension" ); + D(fprintf(stderr, "%*c+ invalid_comprehension[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'[' '**' expression for_if_clauses")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use dict unpacking in list comprehension" ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; p->level--; @@ -22431,7 +22734,40 @@ invalid_comprehension_rule(Parser *p) } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_comprehension[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'[' '**' expression for_if_clauses")); + } + { // '(' '**' expression for_if_clauses + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' '**' expression for_if_clauses")); + Token * _literal; + Token * a; + expr_ty b; + asdl_comprehension_seq* for_if_clauses_var; + if ( + (_literal = _PyPegen_expect_token(p, 7)) // token='(' + && + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (b = expression_rule(p)) // expression + && + (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses + ) + { + D(fprintf(stderr, "%*c+ invalid_comprehension[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' '**' expression for_if_clauses")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use dict unpacking in generator expression" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_comprehension[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' '**' expression for_if_clauses")); } { // ('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses if (p->error_indicator) { @@ -22440,12 +22776,12 @@ invalid_comprehension_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses")); Token * _literal; - void *_tmp_122_var; + void *_tmp_123_var; expr_ty a; asdl_expr_seq* b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_122_var = _tmp_122_rule(p)) // '[' | '{' + (_tmp_123_var = _tmp_123_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -22475,12 +22811,12 @@ invalid_comprehension_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses")); - void *_tmp_122_var; + void *_tmp_123_var; expr_ty a; Token * b; asdl_comprehension_seq* for_if_clauses_var; if ( - (_tmp_122_var = _tmp_122_rule(p)) // '[' | '{' + (_tmp_123_var = _tmp_123_rule(p)) // '[' | '{' && (a = star_named_expression_rule(p)) // star_named_expression && @@ -22508,61 +22844,6 @@ invalid_comprehension_rule(Parser *p) return _res; } -// invalid_dict_comprehension: '{' '**' bitwise_or for_if_clauses '}' -static void * -invalid_dict_comprehension_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '{' '**' bitwise_or for_if_clauses '}' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> invalid_dict_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '**' bitwise_or for_if_clauses '}'")); - Token * _literal; - Token * _literal_1; - Token * a; - expr_ty bitwise_or_var; - asdl_comprehension_seq* for_if_clauses_var; - if ( - (_literal = _PyPegen_expect_token(p, 25)) // token='{' - && - (a = _PyPegen_expect_token(p, 35)) // token='**' - && - (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or - && - (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses - && - (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}' - ) - { - D(fprintf(stderr, "%*c+ invalid_dict_comprehension[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '**' bitwise_or for_if_clauses '}'")); - _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "dict unpacking cannot be used in dict comprehension" ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s invalid_dict_comprehension[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '**' bitwise_or for_if_clauses '}'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - // invalid_parameters: // | "/" ',' // | (slash_no_default | slash_with_default) param_maybe_default* '/' @@ -22616,10 +22897,10 @@ invalid_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'")); asdl_seq * _loop0_31_var; - void *_tmp_123_var; + void *_tmp_124_var; Token * a; if ( - (_tmp_123_var = _tmp_123_rule(p)) // slash_no_default | slash_with_default + (_tmp_124_var = _tmp_124_rule(p)) // slash_no_default | slash_with_default && (_loop0_31_var = _loop0_31_rule(p)) // param_maybe_default* && @@ -22721,16 +23002,16 @@ invalid_parameters_rule(Parser *p) asdl_seq * _loop0_31_var_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_124_var; + void *_tmp_125_var; Token * a; if ( - (_opt_var = _tmp_123_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] + (_opt_var = _tmp_124_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)] && (_loop0_31_var = _loop0_31_rule(p)) // param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_124_var = _tmp_124_rule(p)) // ',' | param_no_default + (_tmp_125_var = _tmp_125_rule(p)) // ',' | param_no_default && (_loop0_31_var_1 = _loop0_31_rule(p)) // param_maybe_default* && @@ -22809,7 +23090,7 @@ invalid_default_rule(Parser *p) if ( (a = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(1, _tmp_125_rule, p) + _PyPegen_lookahead(1, _tmp_126_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')")); @@ -22854,12 +23135,12 @@ invalid_star_etc_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); - void *_tmp_126_var; + void *_tmp_127_var; Token * a; if ( (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_126_var = _tmp_126_rule(p)) // ')' | ',' (')' | '**') + (_tmp_127_var = _tmp_127_rule(p)) // ')' | ',' (')' | '**') ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))")); @@ -22943,19 +23224,19 @@ invalid_star_etc_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); Token * _literal; asdl_seq * _loop0_31_var; - void *_tmp_127_var; - void *_tmp_127_var_1; + void *_tmp_128_var; + void *_tmp_128_var_1; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_127_var = _tmp_127_rule(p)) // param_no_default | ',' + (_tmp_128_var = _tmp_128_rule(p)) // param_no_default | ',' && (_loop0_31_var = _loop0_31_rule(p)) // param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_127_var_1 = _tmp_127_rule(p)) // param_no_default | ',' + (_tmp_128_var_1 = _tmp_128_rule(p)) // param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')")); @@ -23070,7 +23351,7 @@ invalid_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_128_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_129_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')")); @@ -23206,13 +23487,13 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'")); - asdl_seq * _loop0_74_var; - void *_tmp_129_var; + asdl_seq * _loop0_76_var; + void *_tmp_130_var; Token * a; if ( - (_tmp_129_var = _tmp_129_rule(p)) // lambda_slash_no_default | lambda_slash_with_default + (_tmp_130_var = _tmp_130_rule(p)) // lambda_slash_no_default | lambda_slash_with_default && - (_loop0_74_var = _loop0_74_rule(p)) // lambda_param_maybe_default* + (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -23236,7 +23517,7 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default")); - asdl_seq * _loop0_70_var; + asdl_seq * _loop0_72_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings arg_ty a; @@ -23244,7 +23525,7 @@ invalid_lambda_parameters_rule(Parser *p) if ( (_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default? && - (_loop0_70_var = _loop0_70_rule(p)) // lambda_param_no_default* + (_loop0_72_var = _loop0_72_rule(p)) // lambda_param_no_default* && (invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper && @@ -23270,18 +23551,18 @@ invalid_lambda_parameters_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'")); - asdl_seq * _gather_131_var; - asdl_seq * _loop0_70_var; + asdl_seq * _gather_132_var; + asdl_seq * _loop0_72_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * b; if ( - (_loop0_70_var = _loop0_70_rule(p)) // lambda_param_no_default* + (_loop0_72_var = _loop0_72_rule(p)) // lambda_param_no_default* && (a = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_131_var = _gather_131_rule(p)) // ','.lambda_param+ + (_gather_132_var = _gather_132_rule(p)) // ','.lambda_param+ && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -23308,22 +23589,22 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'")); Token * _literal; - asdl_seq * _loop0_74_var; - asdl_seq * _loop0_74_var_1; + asdl_seq * _loop0_76_var; + asdl_seq * _loop0_76_var_1; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_132_var; + void *_tmp_133_var; Token * a; if ( - (_opt_var = _tmp_129_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] + (_opt_var = _tmp_130_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)] && - (_loop0_74_var = _loop0_74_rule(p)) // lambda_param_maybe_default* + (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_132_var = _tmp_132_rule(p)) // ',' | lambda_param_no_default + (_tmp_133_var = _tmp_133_rule(p)) // ',' | lambda_param_no_default && - (_loop0_74_var_1 = _loop0_74_rule(p)) // lambda_param_maybe_default* + (_loop0_76_var_1 = _loop0_76_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 17)) // token='/' ) @@ -23348,10 +23629,10 @@ invalid_lambda_parameters_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'")); Token * _literal; - asdl_seq * _loop1_75_var; + asdl_seq * _loop1_77_var; Token * a; if ( - (_loop1_75_var = _loop1_75_rule(p)) // lambda_param_maybe_default+ + (_loop1_77_var = _loop1_77_rule(p)) // lambda_param_maybe_default+ && (_literal = _PyPegen_expect_token(p, 17)) // token='/' && @@ -23422,13 +23703,13 @@ invalid_lambda_parameters_helper_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - asdl_seq * _loop1_73_var; + asdl_seq * _loop1_75_var; if ( - (_loop1_73_var = _loop1_73_rule(p)) // lambda_param_with_default+ + (_loop1_75_var = _loop1_75_rule(p)) // lambda_param_with_default+ ) { D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+")); - _res = _loop1_73_var; + _res = _loop1_75_var; goto done; } p->mark = _mark; @@ -23464,11 +23745,11 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); Token * _literal; - void *_tmp_133_var; + void *_tmp_134_var; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_133_var = _tmp_133_rule(p)) // ':' | ',' (':' | '**') + (_tmp_134_var = _tmp_134_rule(p)) // ':' | ',' (':' | '**') ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))")); @@ -23521,20 +23802,20 @@ invalid_lambda_star_etc_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); Token * _literal; - asdl_seq * _loop0_74_var; - void *_tmp_134_var; - void *_tmp_134_var_1; + asdl_seq * _loop0_76_var; + void *_tmp_135_var; + void *_tmp_135_var_1; Token * a; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_134_var = _tmp_134_rule(p)) // lambda_param_no_default | ',' + (_tmp_135_var = _tmp_135_rule(p)) // lambda_param_no_default | ',' && - (_loop0_74_var = _loop0_74_rule(p)) // lambda_param_maybe_default* + (_loop0_76_var = _loop0_76_rule(p)) // lambda_param_maybe_default* && (a = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_134_var_1 = _tmp_134_rule(p)) // lambda_param_no_default | ',' + (_tmp_135_var_1 = _tmp_135_rule(p)) // lambda_param_no_default | ',' ) { D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')")); @@ -23652,7 +23933,7 @@ invalid_lambda_kwds_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 12)) // token=',' && - (a = (Token*)_tmp_128_rule(p)) // '*' | '**' | '/' + (a = (Token*)_tmp_129_rule(p)) // '*' | '**' | '/' ) { D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')")); @@ -23754,7 +24035,7 @@ invalid_with_item_rule(Parser *p) if ( (expression_var = expression_rule(p)) // expression && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (a = expression_rule(p)) // expression && @@ -23802,15 +24083,15 @@ invalid_for_if_clause_rule(Parser *p) Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings - void *_tmp_135_var; + void *_tmp_136_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' && - (_tmp_135_var = _tmp_135_rule(p)) // bitwise_or ((',' bitwise_or))* ','? + (_tmp_136_var = _tmp_136_rule(p)) // bitwise_or ((',' bitwise_or))* ','? && - _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 704) // token='in' + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 708) // token='in' ) { D(fprintf(stderr, "%*c+ invalid_for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'? 'for' (bitwise_or ((',' bitwise_or))* ','?) !'in'")); @@ -23856,9 +24137,9 @@ invalid_for_target_rule(Parser *p) UNUSED(_opt_var); // Silence compiler warnings expr_ty a; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' && (a = star_expressions_rule(p)) // star_expressions ) @@ -23983,16 +24264,16 @@ invalid_import_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_import[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import' ','.dotted_name+ 'from' dotted_name")); - asdl_seq * _gather_137_var; + asdl_seq * _gather_138_var; Token * _keyword; Token * a; expr_ty dotted_name_var; if ( - (a = _PyPegen_expect_token(p, 643)) // token='import' + (a = _PyPegen_expect_token(p, 647)) // token='import' && - (_gather_137_var = _gather_137_rule(p)) // ','.dotted_name+ + (_gather_138_var = _gather_138_rule(p)) // ','.dotted_name+ && - (_keyword = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword = _PyPegen_expect_token(p, 646)) // token='from' && (dotted_name_var = dotted_name_rule(p)) // dotted_name ) @@ -24019,7 +24300,7 @@ invalid_import_rule(Parser *p) Token * _keyword; Token * token; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='import' + (_keyword = _PyPegen_expect_token(p, 647)) // token='import' && (token = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24068,9 +24349,9 @@ invalid_dotted_as_name_rule(Parser *p) if ( (dotted_name_var = dotted_name_rule(p)) // dotted_name && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && - _PyPegen_lookahead(0, _tmp_138_rule, p) + _PyPegen_lookahead(0, _tmp_139_rule, p) && (a = expression_rule(p)) // expression ) @@ -24119,9 +24400,9 @@ invalid_import_from_as_name_rule(Parser *p) if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && - _PyPegen_lookahead(0, _tmp_138_rule, p) + _PyPegen_lookahead(0, _tmp_139_rule, p) && (a = expression_rule(p)) // expression ) @@ -24239,17 +24520,17 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' ','.(expression ['as' star_target])+ NEWLINE")); - asdl_seq * _gather_140_var; + asdl_seq * _gather_141_var; Token * _keyword; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword = _PyPegen_expect_token(p, 660)) // token='with' && - (_gather_140_var = _gather_140_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24273,7 +24554,7 @@ invalid_with_stmt_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE")); - asdl_seq * _gather_142_var; + asdl_seq * _gather_143_var; Token * _keyword; Token * _literal; Token * _literal_1; @@ -24283,13 +24564,13 @@ invalid_with_stmt_rule(Parser *p) UNUSED(_opt_var_1); // Silence compiler warnings Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword = _PyPegen_expect_token(p, 660)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_142_var = _gather_142_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_143_var = _gather_143_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -24338,18 +24619,18 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT")); - asdl_seq * _gather_140_var; + asdl_seq * _gather_141_var; Token * _literal; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 656)) // token='with' + (a = _PyPegen_expect_token(p, 660)) // token='with' && - (_gather_140_var = _gather_140_rule(p)) // ','.(expression ['as' star_target])+ + (_gather_141_var = _gather_141_rule(p)) // ','.(expression ['as' star_target])+ && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24377,7 +24658,7 @@ invalid_with_stmt_indent_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT")); - asdl_seq * _gather_142_var; + asdl_seq * _gather_143_var; Token * _literal; Token * _literal_1; Token * _literal_2; @@ -24388,13 +24669,13 @@ invalid_with_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 656)) // token='with' + (a = _PyPegen_expect_token(p, 660)) // token='with' && (_literal = _PyPegen_expect_token(p, 7)) // token='(' && - (_gather_142_var = _gather_142_rule(p)) // ','.(expressions ['as' star_target])+ + (_gather_143_var = _gather_143_rule(p)) // ','.(expressions ['as' star_target])+ && (_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? && @@ -24453,7 +24734,7 @@ invalid_try_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 665)) // token='try' + (a = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -24485,13 +24766,13 @@ invalid_try_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - _PyPegen_lookahead(0, _tmp_143_rule, p) + _PyPegen_lookahead(0, _tmp_144_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')")); @@ -24516,7 +24797,7 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_144_var; + asdl_seq * _loop0_145_var; asdl_seq * _loop1_36_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings @@ -24524,15 +24805,15 @@ invalid_try_stmt_rule(Parser *p) Token * b; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_144_var = _loop0_144_rule(p)) // block* + (_loop0_145_var = _loop0_145_rule(p)) // block* && (_loop1_36_var = _loop1_36_rule(p)) // except_block+ && - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (b = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24565,23 +24846,23 @@ invalid_try_stmt_rule(Parser *p) Token * _keyword; Token * _literal; Token * _literal_1; - asdl_seq * _loop0_144_var; + asdl_seq * _loop0_145_var; asdl_seq * _loop1_37_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings Token * a; if ( - (_keyword = _PyPegen_expect_token(p, 665)) // token='try' + (_keyword = _PyPegen_expect_token(p, 669)) // token='try' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_144_var = _loop0_144_rule(p)) // block* + (_loop0_145_var = _loop0_145_rule(p)) // block* && (_loop1_37_var = _loop1_37_rule(p)) // except_star_block+ && - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && - (_opt_var = _tmp_145_rule(p), !p->error_indicator) // [expression ['as' NAME]] + (_opt_var = _tmp_146_rule(p), !p->error_indicator) // [expression ['as' NAME]] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' ) @@ -24636,7 +24917,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (a = expression_rule(p)) // expression && @@ -24644,7 +24925,7 @@ invalid_except_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -24676,7 +24957,7 @@ invalid_except_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -24707,7 +24988,7 @@ invalid_except_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) @@ -24738,11 +25019,11 @@ invalid_except_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (a = expression_rule(p)) // expression && @@ -24802,7 +25083,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expressions_var; expr_ty name_var; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24812,7 +25093,7 @@ invalid_except_star_stmt_rule(Parser *p) && (expressions_var = expressions_rule(p)) // expressions && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -24845,7 +25126,7 @@ invalid_except_star_stmt_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -24876,14 +25157,14 @@ invalid_except_star_stmt_rule(Parser *p) } D(fprintf(stderr, "%*c> invalid_except_star_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); Token * _literal; - void *_tmp_146_var; + void *_tmp_147_var; Token * a; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && - (_tmp_146_var = _tmp_146_rule(p)) // NEWLINE | ':' + (_tmp_147_var = _tmp_147_rule(p)) // NEWLINE | ':' ) { D(fprintf(stderr, "%*c+ invalid_except_star_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')")); @@ -24913,13 +25194,13 @@ invalid_except_star_stmt_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty expression_var; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && (expression_var = expression_rule(p)) // expression && - (_keyword_1 = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword_1 = _PyPegen_expect_token(p, 693)) // token='as' && (a = expression_rule(p)) // expression && @@ -24970,7 +25251,7 @@ invalid_finally_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 682)) // token='finally' + (a = _PyPegen_expect_token(p, 686)) // token='finally' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25026,7 +25307,7 @@ invalid_except_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (expression_var = expression_rule(p)) // expression && @@ -25062,7 +25343,7 @@ invalid_except_stmt_indent_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25118,7 +25399,7 @@ invalid_except_star_stmt_indent_rule(Parser *p) expr_ty expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 686)) // token='except' + (a = _PyPegen_expect_token(p, 690)) // token='except' && (_literal = _PyPegen_expect_token(p, 16)) // token='*' && @@ -25395,7 +25676,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"' ) @@ -25425,7 +25706,7 @@ invalid_as_pattern_rule(Parser *p) if ( (or_pattern_var = or_pattern_rule(p)) // or_pattern && - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (a = expression_rule(p)) // expression ) @@ -25530,7 +25811,7 @@ invalid_mapping_pattern_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 25)) // token='{' && - (_opt_var = _tmp_147_rule(p), !p->error_indicator) // [(items_pattern ',')] + (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [(items_pattern ',')] && (rest = double_star_pattern_rule(p)) // double_star_pattern && @@ -25588,7 +25869,7 @@ invalid_class_argument_pattern_rule(Parser *p) asdl_pattern_seq* a; asdl_seq* keyword_patterns_var; if ( - (_opt_var = _tmp_148_rule(p), !p->error_indicator) // [positional_patterns ','] + (_opt_var = _tmp_149_rule(p), !p->error_indicator) // [positional_patterns ','] && (keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns && @@ -25641,7 +25922,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25672,7 +25953,7 @@ invalid_if_stmt_rule(Parser *p) expr_ty a_1; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 691)) // token='if' + (a = _PyPegen_expect_token(p, 695)) // token='if' && (a_1 = named_expression_rule(p)) // named_expression && @@ -25727,7 +26008,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 696)) // token='elif' + (_keyword = _PyPegen_expect_token(p, 700)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25758,7 +26039,7 @@ invalid_elif_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 696)) // token='elif' + (a = _PyPegen_expect_token(p, 700)) // token='elif' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25811,7 +26092,7 @@ invalid_else_stmt_rule(Parser *p) Token * a; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 695)) // token='else' + (a = _PyPegen_expect_token(p, 699)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && @@ -25844,13 +26125,13 @@ invalid_else_stmt_rule(Parser *p) Token * _literal; asdl_stmt_seq* block_var; if ( - (_keyword = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword = _PyPegen_expect_token(p, 699)) // token='else' && (_literal = _PyPegen_expect_token(p, 11)) // token=':' && (block_var = block_rule(p)) // block && - (_keyword_1 = _PyPegen_expect_token(p, 696)) // token='elif' + (_keyword_1 = _PyPegen_expect_token(p, 700)) // token='elif' ) { D(fprintf(stderr, "%*c+ invalid_else_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else' ':' block 'elif'")); @@ -25897,7 +26178,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 698)) // token='while' + (_keyword = _PyPegen_expect_token(p, 702)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25928,7 +26209,7 @@ invalid_while_stmt_rule(Parser *p) expr_ty named_expression_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 698)) // token='while' + (a = _PyPegen_expect_token(p, 702)) // token='while' && (named_expression_var = named_expression_rule(p)) // named_expression && @@ -25987,13 +26268,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword_1 = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword_1 = _PyPegen_expect_token(p, 708)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26028,13 +26309,13 @@ invalid_for_stmt_rule(Parser *p) expr_ty star_expressions_var; expr_ty star_targets_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 703)) // token='for' + (a = _PyPegen_expect_token(p, 707)) // token='for' && (star_targets_var = star_targets_rule(p)) // star_targets && - (_keyword = _PyPegen_expect_token(p, 704)) // token='in' + (_keyword = _PyPegen_expect_token(p, 708)) // token='in' && (star_expressions_var = star_expressions_rule(p)) // star_expressions && @@ -26100,9 +26381,9 @@ invalid_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (a = _PyPegen_expect_token(p, 708)) // token='def' + (a = _PyPegen_expect_token(p, 712)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26159,9 +26440,9 @@ invalid_def_raw_rule(Parser *p) asdl_stmt_seq* block_var; expr_ty name_var; if ( - (_opt_var = _PyPegen_expect_token(p, 707), !p->error_indicator) // 'async'? + (_opt_var = _PyPegen_expect_token(p, 711), !p->error_indicator) // 'async'? && - (_keyword = _PyPegen_expect_token(p, 708)) // token='def' + (_keyword = _PyPegen_expect_token(p, 712)) // token='def' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26225,7 +26506,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='class' + (_keyword = _PyPegen_expect_token(p, 714)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26264,7 +26545,7 @@ invalid_class_def_raw_rule(Parser *p) expr_ty name_var; Token * newline_var; if ( - (a = _PyPegen_expect_token(p, 710)) // token='class' + (a = _PyPegen_expect_token(p, 714)) // token='class' && (name_var = _PyPegen_name_token(p)) // NAME && @@ -26299,8 +26580,8 @@ invalid_class_def_raw_rule(Parser *p) } // invalid_double_starred_kvpairs: -// | ','.double_starred_kvpair+ ',' invalid_kvpair -// | expression ':' '*' bitwise_or +// | invalid_kvpair_unpacking ','? +// | ','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking) // | expression ':' &('}' | ',') static void * invalid_double_starred_kvpairs_rule(Parser *p) @@ -26314,63 +26595,53 @@ invalid_double_starred_kvpairs_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // ','.double_starred_kvpair+ ',' invalid_kvpair + { // invalid_kvpair_unpacking ','? if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - asdl_seq * _gather_84_var; - Token * _literal; - void *invalid_kvpair_var; + D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_kvpair_unpacking ','?")); + void *_opt_var; + UNUSED(_opt_var); // Silence compiler warnings + void *invalid_kvpair_unpacking_var; if ( - (_gather_84_var = _gather_84_rule(p)) // ','.double_starred_kvpair+ + (invalid_kvpair_unpacking_var = invalid_kvpair_unpacking_rule(p)) // invalid_kvpair_unpacking + && + (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? + ) + { + D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_kvpair_unpacking ','?")); + _res = _PyPegen_dummy_name(p, invalid_kvpair_unpacking_var, _opt_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_double_starred_kvpairs[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_kvpair_unpacking ','?")); + } + { // ','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking)")); + asdl_seq * _gather_86_var; + Token * _literal; + void *_tmp_150_var; + if ( + (_gather_86_var = _gather_86_rule(p)) // ','.double_starred_kvpair+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (invalid_kvpair_var = invalid_kvpair_rule(p)) // invalid_kvpair + (_tmp_150_var = _tmp_150_rule(p)) // invalid_kvpair | invalid_kvpair_unpacking ) { - D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - _res = _PyPegen_dummy_name(p, _gather_84_var, _literal, invalid_kvpair_var); + D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking)")); + _res = _PyPegen_dummy_name(p, _gather_86_var, _literal, _tmp_150_var); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s invalid_double_starred_kvpairs[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair")); - } - { // expression ':' '*' bitwise_or - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ':' '*' bitwise_or")); - Token * _literal; - Token * a; - expr_ty bitwise_or_var; - expr_ty expression_var; - if ( - (expression_var = expression_rule(p)) // expression - && - (_literal = _PyPegen_expect_token(p, 11)) // token=':' - && - (a = _PyPegen_expect_token(p, 16)) // token='*' - && - (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or - ) - { - D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' '*' bitwise_or")); - _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( a , "cannot use a starred expression in a dictionary value" ); - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s invalid_double_starred_kvpairs[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ':' '*' bitwise_or")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking)")); } { // expression ':' &('}' | ',') if (p->error_indicator) { @@ -26385,7 +26656,7 @@ invalid_double_starred_kvpairs_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_149_rule, p) + _PyPegen_lookahead(1, _tmp_151_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -26407,9 +26678,193 @@ invalid_double_starred_kvpairs_rule(Parser *p) return _res; } +// invalid_kvpair_unpacking: +// | '**' if_expression +// | '*' bitwise_or ':' expression +// | '**' bitwise_or ':' expression +// | expression ':' '*' bitwise_or +// | expression ':' '**' bitwise_or +static void * +invalid_kvpair_unpacking_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '**' if_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' if_expression")); + Token * a; + expr_ty b; + if ( + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (b = if_expression_rule(p)) // if_expression + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' if_expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "invalid double starred expression. Did you forget to wrap the conditional expression in parentheses?" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' if_expression")); + } + { // '*' bitwise_or ':' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' bitwise_or ':' expression")); + Token * _literal; + Token * a; + expr_ty b; + expr_ty expression_var; + if ( + (a = _PyPegen_expect_token(p, 16)) // token='*' + && + (b = bitwise_or_rule(p)) // bitwise_or + && + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (expression_var = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' bitwise_or ':' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use a starred expression in a dictionary key" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' bitwise_or ':' expression")); + } + { // '**' bitwise_or ':' expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' bitwise_or ':' expression")); + Token * _literal; + Token * a; + expr_ty b; + expr_ty expression_var; + if ( + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (b = bitwise_or_rule(p)) // bitwise_or + && + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (expression_var = expression_rule(p)) // expression + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' bitwise_or ':' expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use dict unpacking in a dictionary key" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' bitwise_or ':' expression")); + } + { // expression ':' '*' bitwise_or + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ':' '*' bitwise_or")); + Token * _literal; + Token * a; + expr_ty b; + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (a = _PyPegen_expect_token(p, 16)) // token='*' + && + (b = bitwise_or_rule(p)) // bitwise_or + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' '*' bitwise_or")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use a starred expression in a dictionary value" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ':' '*' bitwise_or")); + } + { // expression ':' '**' bitwise_or + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ':' '**' bitwise_or")); + Token * _literal; + Token * a; + expr_ty b; + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (b = bitwise_or_rule(p)) // bitwise_or + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' '**' bitwise_or")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "cannot use dict unpacking in a dictionary value" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ':' '**' bitwise_or")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_kvpair: // | expression !(':') // | expression ':' '*' bitwise_or +// | expression ':' '**' bitwise_or // | expression ':' &('}' | ',') static void * invalid_kvpair_rule(Parser *p) @@ -26482,6 +26937,39 @@ invalid_kvpair_rule(Parser *p) D(fprintf(stderr, "%*c%s invalid_kvpair[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ':' '*' bitwise_or")); } + { // expression ':' '**' bitwise_or + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_kvpair[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ':' '**' bitwise_or")); + Token * _literal; + Token * a; + expr_ty bitwise_or_var; + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression + && + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + && + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or + ) + { + D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' '**' bitwise_or")); + _res = RAISE_SYNTAX_ERROR_STARTING_FROM ( a , "cannot use dict unpacking in a dictionary value" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_kvpair[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ':' '**' bitwise_or")); + } { // expression ':' &('}' | ',') if (p->error_indicator) { p->level--; @@ -26495,7 +26983,7 @@ invalid_kvpair_rule(Parser *p) && (a = _PyPegen_expect_token(p, 11)) // token=':' && - _PyPegen_lookahead(1, _tmp_149_rule, p) + _PyPegen_lookahead(1, _tmp_151_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')")); @@ -26517,7 +27005,7 @@ invalid_kvpair_rule(Parser *p) return _res; } -// invalid_starred_expression_unpacking: '*' expression '=' expression +// invalid_starred_expression_unpacking: '*' if_expression | '*' expression '=' expression static void * invalid_starred_expression_unpacking_rule(Parser *p) { @@ -26530,6 +27018,33 @@ invalid_starred_expression_unpacking_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; + { // '*' if_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_starred_expression_unpacking[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' if_expression")); + Token * a; + expr_ty b; + if ( + (a = _PyPegen_expect_token(p, 16)) // token='*' + && + (b = if_expression_rule(p)) // if_expression + ) + { + D(fprintf(stderr, "%*c+ invalid_starred_expression_unpacking[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' if_expression")); + _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "invalid starred expression. Did you forget to wrap the conditional expression in parentheses?" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_starred_expression_unpacking[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*' if_expression")); + } { // '*' expression '=' expression if (p->error_indicator) { p->level--; @@ -26569,6 +27084,73 @@ invalid_starred_expression_unpacking_rule(Parser *p) return _res; } +// invalid_starred_expression_unpacking_sequence: +// | '**' bitwise_or +// | invalid_starred_expression_unpacking +static void * +invalid_starred_expression_unpacking_sequence_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '**' bitwise_or + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_starred_expression_unpacking_sequence[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**' bitwise_or")); + Token * a; + expr_ty bitwise_or_var; + if ( + (a = _PyPegen_expect_token(p, 35)) // token='**' + && + (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or + ) + { + D(fprintf(stderr, "%*c+ invalid_starred_expression_unpacking_sequence[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' bitwise_or")); + _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "cannot use dict unpacking here" ); + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_starred_expression_unpacking_sequence[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**' bitwise_or")); + } + if (p->call_invalid_rules) { // invalid_starred_expression_unpacking + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> invalid_starred_expression_unpacking_sequence[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_starred_expression_unpacking")); + void *invalid_starred_expression_unpacking_var; + if ( + (invalid_starred_expression_unpacking_var = invalid_starred_expression_unpacking_rule(p)) // invalid_starred_expression_unpacking + ) + { + D(fprintf(stderr, "%*c+ invalid_starred_expression_unpacking_sequence[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_starred_expression_unpacking")); + _res = invalid_starred_expression_unpacking_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s invalid_starred_expression_unpacking_sequence[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_starred_expression_unpacking")); + } + _res = NULL; + done: + p->level--; + return _res; +} + // invalid_starred_expression: '*' static void * invalid_starred_expression_rule(Parser *p) @@ -26783,7 +27365,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (annotated_rhs_var = annotated_rhs_rule(p)) // annotated_rhs && - _PyPegen_lookahead(0, _tmp_150_rule, p) + _PyPegen_lookahead(0, _tmp_152_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | ':' | '}')")); @@ -26815,7 +27397,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_151_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | ':' | '}')")); @@ -26879,9 +27461,9 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_153_rule, p) + _PyPegen_lookahead(0, _tmp_155_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] !(':' | '}')")); @@ -26905,7 +27487,7 @@ invalid_fstring_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_76_var; + asdl_seq * _loop0_78_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; @@ -26918,11 +27500,11 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_76_var = _loop0_76_rule(p)) // fstring_format_spec* + (_loop0_78_var = _loop0_78_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -26959,7 +27541,7 @@ invalid_fstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -27006,7 +27588,7 @@ invalid_fstring_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_153_rule, p) + _PyPegen_lookahead(1, _tmp_155_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_fstring_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -27225,7 +27807,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (annotated_rhs_var = annotated_rhs_rule(p)) // annotated_rhs && - _PyPegen_lookahead(0, _tmp_150_rule, p) + _PyPegen_lookahead(0, _tmp_152_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs !('=' | '!' | ':' | '}')")); @@ -27257,7 +27839,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_literal_1 = _PyPegen_expect_token(p, 22)) // token='=' && - _PyPegen_lookahead(0, _tmp_151_rule, p) + _PyPegen_lookahead(0, _tmp_153_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '=' !('!' | ':' | '}')")); @@ -27321,9 +27903,9 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && - _PyPegen_lookahead(0, _tmp_153_rule, p) + _PyPegen_lookahead(0, _tmp_155_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] !(':' | '}')")); @@ -27347,7 +27929,7 @@ invalid_tstring_replacement_field_rule(Parser *p) D(fprintf(stderr, "%*c> invalid_tstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' annotated_rhs '='? ['!' NAME] ':' fstring_format_spec* !'}'")); Token * _literal; Token * _literal_1; - asdl_seq * _loop0_76_var; + asdl_seq * _loop0_78_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings void *_opt_var_1; @@ -27360,11 +27942,11 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':' && - (_loop0_76_var = _loop0_76_rule(p)) // fstring_format_spec* + (_loop0_78_var = _loop0_78_rule(p)) // fstring_format_spec* && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -27401,7 +27983,7 @@ invalid_tstring_replacement_field_rule(Parser *p) && (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='? && - (_opt_var_1 = _tmp_152_rule(p), !p->error_indicator) // ['!' NAME] + (_opt_var_1 = _tmp_154_rule(p), !p->error_indicator) // ['!' NAME] && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}' ) @@ -27448,7 +28030,7 @@ invalid_tstring_conversion_character_rule(Parser *p) if ( (_literal = _PyPegen_expect_token(p, 54)) // token='!' && - _PyPegen_lookahead(1, _tmp_153_rule, p) + _PyPegen_lookahead(1, _tmp_155_rule, p) ) { D(fprintf(stderr, "%*c+ invalid_tstring_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')")); @@ -27520,7 +28102,7 @@ invalid_string_tstring_concat_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _loop1_80_rule(p)) // ((fstring | string))+ + (a = _loop1_82_rule(p)) // ((fstring | string))+ && (b = (expr_ty)tstring_rule(p)) // tstring ) @@ -27547,9 +28129,9 @@ invalid_string_tstring_concat_rule(Parser *p) asdl_seq * a; expr_ty b; if ( - (a = _loop1_81_rule(p)) // tstring+ + (a = _loop1_83_rule(p)) // tstring+ && - (b = (expr_ty)_tmp_154_rule(p)) // fstring | string + (b = (expr_ty)_tmp_156_rule(p)) // fstring | string ) { D(fprintf(stderr, "%*c+ invalid_string_tstring_concat[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tstring+ (fstring | string)")); @@ -27590,16 +28172,16 @@ invalid_arithmetic_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_arithmetic[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "sum ('+' | '-' | '*' | '/' | '%' | '//' | '@') 'not' inversion")); - void *_tmp_155_var; + void *_tmp_157_var; Token * a; expr_ty b; expr_ty sum_var; if ( (sum_var = sum_rule(p)) // sum && - (_tmp_155_var = _tmp_155_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' + (_tmp_157_var = _tmp_157_rule(p)) // '+' | '-' | '*' | '/' | '%' | '//' | '@' && - (a = _PyPegen_expect_token(p, 712)) // token='not' + (a = _PyPegen_expect_token(p, 716)) // token='not' && (b = inversion_rule(p)) // inversion ) @@ -27642,13 +28224,13 @@ invalid_factor_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> invalid_factor[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('+' | '-' | '~') 'not' factor")); - void *_tmp_156_var; + void *_tmp_158_var; Token * a; expr_ty b; if ( - (_tmp_156_var = _tmp_156_rule(p)) // '+' | '-' | '~' + (_tmp_158_var = _tmp_158_rule(p)) // '+' | '-' | '~' && - (a = _PyPegen_expect_token(p, 712)) // token='not' + (a = _PyPegen_expect_token(p, 716)) // token='not' && (b = factor_rule(p)) // factor ) @@ -27995,7 +28577,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 643)) // token='import' + (_keyword = _PyPegen_expect_token(p, 647)) // token='import' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'")); @@ -28014,7 +28596,7 @@ _tmp_5_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 642)) // token='from' + (_keyword = _PyPegen_expect_token(p, 646)) // token='from' ) { D(fprintf(stderr, "%*c+ _tmp_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'")); @@ -28052,7 +28634,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 708)) // token='def' + (_keyword = _PyPegen_expect_token(p, 712)) // token='def' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'")); @@ -28090,7 +28672,7 @@ _tmp_6_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28128,7 +28710,7 @@ _tmp_7_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 710)) // token='class' + (_keyword = _PyPegen_expect_token(p, 714)) // token='class' ) { D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'")); @@ -28185,7 +28767,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 656)) // token='with' + (_keyword = _PyPegen_expect_token(p, 660)) // token='with' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'")); @@ -28204,7 +28786,7 @@ _tmp_8_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28242,7 +28824,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 703)) // token='for' + (_keyword = _PyPegen_expect_token(p, 707)) // token='for' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'")); @@ -28261,7 +28843,7 @@ _tmp_9_rule(Parser *p) D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'async'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 707)) // token='async' + (_keyword = _PyPegen_expect_token(p, 711)) // token='async' ) { D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'async'")); @@ -28420,12 +29002,12 @@ _loop1_12_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_157_var; + void *_tmp_159_var; while ( - (_tmp_157_var = _tmp_157_rule(p)) // star_targets '=' + (_tmp_159_var = _tmp_159_rule(p)) // star_targets '=' ) { - _res = _tmp_157_var; + _res = _tmp_159_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28712,12 +29294,12 @@ _loop0_17_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop0_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_158_var; + void *_tmp_160_var; while ( - (_tmp_158_var = _tmp_158_rule(p)) // '.' | '...' + (_tmp_160_var = _tmp_160_rule(p)) // '.' | '...' ) { - _res = _tmp_158_var; + _res = _tmp_160_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28779,12 +29361,12 @@ _loop1_18_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')")); - void *_tmp_158_var; + void *_tmp_160_var; while ( - (_tmp_158_var = _tmp_158_rule(p)) // '.' | '...' + (_tmp_160_var = _tmp_160_rule(p)) // '.' | '...' ) { - _res = _tmp_158_var; + _res = _tmp_160_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -28962,7 +29544,7 @@ _tmp_21_rule(Parser *p) Token * _keyword; expr_ty z; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (z = _PyPegen_name_token(p)) // NAME ) @@ -29131,12 +29713,12 @@ _loop1_24_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)")); - void *_tmp_159_var; + void *_tmp_161_var; while ( - (_tmp_159_var = _tmp_159_rule(p)) // '@' named_expression NEWLINE + (_tmp_161_var = _tmp_161_rule(p)) // '@' named_expression NEWLINE ) { - _res = _tmp_159_var; + _res = _tmp_161_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31164,12 +31746,12 @@ _loop1_56_rule(Parser *p) return NULL; } D(fprintf(stderr, "%*c> _loop1_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)")); - void *_tmp_160_var; + void *_tmp_162_var; while ( - (_tmp_160_var = _tmp_160_rule(p)) // ',' star_expression + (_tmp_162_var = _tmp_162_rule(p)) // ',' star_expression ) { - _res = _tmp_160_var; + _res = _tmp_162_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31325,9 +31907,126 @@ _gather_58_rule(Parser *p) return _res; } -// _loop1_59: ('or' conjunction) +// _loop0_59: ',' star_named_expression_sequence static asdl_seq * -_loop1_59_rule(Parser *p) +_loop0_59_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' star_named_expression_sequence + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression_sequence")); + Token * _literal; + expr_ty elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = star_named_expression_sequence_rule(p)) // star_named_expression_sequence + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_59[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression_sequence")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_60: star_named_expression_sequence _loop0_59 +static asdl_seq * +_gather_60_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // star_named_expression_sequence _loop0_59 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression_sequence _loop0_59")); + expr_ty elem; + asdl_seq * seq; + if ( + (elem = star_named_expression_sequence_rule(p)) // star_named_expression_sequence + && + (seq = _loop0_59_rule(p)) // _loop0_59 + ) + { + D(fprintf(stderr, "%*c+ _gather_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression_sequence _loop0_59")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_60[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression_sequence _loop0_59")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop1_61: ('or' conjunction) +static asdl_seq * +_loop1_61_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31352,13 +32051,13 @@ _loop1_59_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); - void *_tmp_161_var; + D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)")); + void *_tmp_163_var; while ( - (_tmp_161_var = _tmp_161_rule(p)) // 'or' conjunction + (_tmp_163_var = _tmp_163_rule(p)) // 'or' conjunction ) { - _res = _tmp_161_var; + _res = _tmp_163_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31375,7 +32074,7 @@ _loop1_59_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_59[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)")); } if (_n == 0 || p->error_indicator) { @@ -31397,9 +32096,9 @@ _loop1_59_rule(Parser *p) return _seq; } -// _loop1_60: ('and' inversion) +// _loop1_62: ('and' inversion) static asdl_seq * -_loop1_60_rule(Parser *p) +_loop1_62_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31424,13 +32123,13 @@ _loop1_60_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); - void *_tmp_162_var; + D(fprintf(stderr, "%*c> _loop1_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)")); + void *_tmp_164_var; while ( - (_tmp_162_var = _tmp_162_rule(p)) // 'and' inversion + (_tmp_164_var = _tmp_164_rule(p)) // 'and' inversion ) { - _res = _tmp_162_var; + _res = _tmp_164_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -31447,7 +32146,7 @@ _loop1_60_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_62[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)")); } if (_n == 0 || p->error_indicator) { @@ -31469,9 +32168,9 @@ _loop1_60_rule(Parser *p) return _seq; } -// _loop1_61: compare_op_bitwise_or_pair +// _loop1_63: compare_op_bitwise_or_pair static asdl_seq * -_loop1_61_rule(Parser *p) +_loop1_63_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31496,7 +32195,7 @@ _loop1_61_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); + D(fprintf(stderr, "%*c> _loop1_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair")); CmpopExprPair* compare_op_bitwise_or_pair_var; while ( (compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair @@ -31519,7 +32218,7 @@ _loop1_61_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_63[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair")); } if (_n == 0 || p->error_indicator) { @@ -31541,9 +32240,9 @@ _loop1_61_rule(Parser *p) return _seq; } -// _tmp_62: '!=' +// _tmp_64: '!=' static void * -_tmp_62_rule(Parser *p) +_tmp_64_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31559,13 +32258,13 @@ _tmp_62_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c> _tmp_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='")); Token * tok; if ( (tok = _PyPegen_expect_token(p, 28)) // token='!=' ) { - D(fprintf(stderr, "%*c+ _tmp_62[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); + D(fprintf(stderr, "%*c+ _tmp_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='")); _res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -31575,7 +32274,7 @@ _tmp_62_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_62[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_64[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='")); } _res = NULL; @@ -31584,9 +32283,9 @@ _tmp_62_rule(Parser *p) return _res; } -// _loop0_63: ',' (slice | starred_expression) +// _loop0_65: ',' (slice | starred_expression) static asdl_seq * -_loop0_63_rule(Parser *p) +_loop0_65_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31611,13 +32310,13 @@ _loop0_63_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); + D(fprintf(stderr, "%*c> _loop0_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_163_rule(p)) // slice | starred_expression + (elem = _tmp_165_rule(p)) // slice | starred_expression ) { _res = elem; @@ -31643,7 +32342,7 @@ _loop0_63_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_63[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_65[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (slice | starred_expression)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -31660,9 +32359,9 @@ _loop0_63_rule(Parser *p) return _seq; } -// _gather_64: (slice | starred_expression) _loop0_63 +// _gather_66: (slice | starred_expression) _loop0_65 static asdl_seq * -_gather_64_rule(Parser *p) +_gather_66_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31673,27 +32372,27 @@ _gather_64_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (slice | starred_expression) _loop0_63 + { // (slice | starred_expression) _loop0_65 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_63")); + D(fprintf(stderr, "%*c> _gather_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_65")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_163_rule(p)) // slice | starred_expression + (elem = _tmp_165_rule(p)) // slice | starred_expression && - (seq = _loop0_63_rule(p)) // _loop0_63 + (seq = _loop0_65_rule(p)) // _loop0_65 ) { - D(fprintf(stderr, "%*c+ _gather_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_63")); + D(fprintf(stderr, "%*c+ _gather_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_65")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_64[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_63")); + D(fprintf(stderr, "%*c%s _gather_66[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_65")); } _res = NULL; done: @@ -31701,9 +32400,9 @@ _gather_64_rule(Parser *p) return _res; } -// _tmp_65: ':' expression? +// _tmp_67: ':' expression? static void * -_tmp_65_rule(Parser *p) +_tmp_67_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31719,7 +32418,7 @@ _tmp_65_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?")); Token * _literal; void *d; if ( @@ -31728,7 +32427,7 @@ _tmp_65_rule(Parser *p) (d = expression_rule(p), !p->error_indicator) // expression? ) { - D(fprintf(stderr, "%*c+ _tmp_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); + D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?")); _res = d; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -31738,7 +32437,7 @@ _tmp_65_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_65[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?")); } _res = NULL; @@ -31747,140 +32446,7 @@ _tmp_65_rule(Parser *p) return _res; } -// _tmp_66: tuple | group | genexp -static void * -_tmp_66_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // tuple - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); - expr_ty tuple_var; - if ( - (tuple_var = tuple_rule(p)) // tuple - ) - { - D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); - _res = tuple_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); - } - { // group - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); - expr_ty group_var; - if ( - (group_var = group_rule(p)) // group - ) - { - D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); - _res = group_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); - } - { // genexp - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); - expr_ty genexp_var; - if ( - (genexp_var = genexp_rule(p)) // genexp - ) - { - D(fprintf(stderr, "%*c+ _tmp_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); - _res = genexp_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_66[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_67: list | listcomp -static void * -_tmp_67_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // list - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); - expr_ty list_var; - if ( - (list_var = list_rule(p)) // list - ) - { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); - _res = list_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); - } - { // listcomp - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); - expr_ty listcomp_var; - if ( - (listcomp_var = listcomp_rule(p)) // listcomp - ) - { - D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); - _res = listcomp_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_68: dict | set | dictcomp | setcomp +// _tmp_68: genexp | tuple | group static void * _tmp_68_rule(Parser *p) { @@ -31893,81 +32459,62 @@ _tmp_68_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // dict + { // genexp if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); - expr_ty dict_var; + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + expr_ty genexp_var; if ( - (dict_var = dict_rule(p)) // dict + (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); - _res = dict_var; + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + _res = genexp_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } - { // set + { // tuple if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); - expr_ty set_var; + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + expr_ty tuple_var; if ( - (set_var = set_rule(p)) // set + (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); - _res = set_var; + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + _res = tuple_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } - { // dictcomp + { // group if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); - expr_ty dictcomp_var; + D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group")); + expr_ty group_var; if ( - (dictcomp_var = dictcomp_rule(p)) // dictcomp + (group_var = group_rule(p)) // group ) { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); - _res = dictcomp_var; + D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group")); + _res = group_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); - } - { // setcomp - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_68[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); - expr_ty setcomp_var; - if ( - (setcomp_var = setcomp_rule(p)) // setcomp - ) - { - D(fprintf(stderr, "%*c+ _tmp_68[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); - _res = setcomp_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_68[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group")); } _res = NULL; done: @@ -31975,9 +32522,161 @@ _tmp_68_rule(Parser *p) return _res; } -// _tmp_69: yield_expr | named_expression +// _tmp_69: listcomp | list static void * _tmp_69_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // listcomp + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp")); + expr_ty listcomp_var; + if ( + (listcomp_var = listcomp_rule(p)) // listcomp + ) + { + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp")); + _res = listcomp_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp")); + } + { // list + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + expr_ty list_var; + if ( + (list_var = list_rule(p)) // list + ) + { + D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + _res = list_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_70: dictcomp | setcomp | dict | set +static void * +_tmp_70_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // dictcomp + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp")); + expr_ty dictcomp_var; + if ( + (dictcomp_var = dictcomp_rule(p)) // dictcomp + ) + { + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp")); + _res = dictcomp_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp")); + } + { // setcomp + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp")); + expr_ty setcomp_var; + if ( + (setcomp_var = setcomp_rule(p)) // setcomp + ) + { + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp")); + _res = setcomp_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp")); + } + { // dict + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict")); + expr_ty dict_var; + if ( + (dict_var = dict_rule(p)) // dict + ) + { + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict")); + _res = dict_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict")); + } + { // set + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set")); + expr_ty set_var; + if ( + (set_var = set_rule(p)) // set + ) + { + D(fprintf(stderr, "%*c+ _tmp_70[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set")); + _res = set_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_70[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_71: yield_expr | named_expression +static void * +_tmp_71_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -31993,18 +32692,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr")); expr_ty yield_expr_var; if ( (yield_expr_var = yield_expr_rule(p)) // yield_expr ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); + D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr")); _res = yield_expr_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr")); } { // named_expression @@ -32012,18 +32711,18 @@ _tmp_69_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression")); expr_ty named_expression_var; if ( (named_expression_var = named_expression_rule(p)) // named_expression ) { - D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); + D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression")); _res = named_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression")); } _res = NULL; @@ -32032,9 +32731,9 @@ _tmp_69_rule(Parser *p) return _res; } -// _loop0_70: lambda_param_no_default +// _loop0_72: lambda_param_no_default static asdl_seq * -_loop0_70_rule(Parser *p) +_loop0_72_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32059,7 +32758,7 @@ _loop0_70_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_70[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -32082,7 +32781,7 @@ _loop0_70_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_70[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32099,9 +32798,9 @@ _loop0_70_rule(Parser *p) return _seq; } -// _loop0_71: lambda_param_with_default +// _loop0_73: lambda_param_with_default static asdl_seq * -_loop0_71_rule(Parser *p) +_loop0_73_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32126,7 +32825,7 @@ _loop0_71_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + D(fprintf(stderr, "%*c> _loop0_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); NameDefaultPair* lambda_param_with_default_var; while ( (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default @@ -32149,7 +32848,7 @@ _loop0_71_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_71[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_73[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32166,9 +32865,9 @@ _loop0_71_rule(Parser *p) return _seq; } -// _loop1_72: lambda_param_no_default +// _loop1_74: lambda_param_no_default static asdl_seq * -_loop1_72_rule(Parser *p) +_loop1_74_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32193,7 +32892,7 @@ _loop1_72_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _loop1_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; while ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default @@ -32216,7 +32915,7 @@ _loop1_72_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_72[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_74[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } if (_n == 0 || p->error_indicator) { @@ -32238,148 +32937,81 @@ _loop1_72_rule(Parser *p) return _seq; } -// _loop1_73: lambda_param_with_default -static asdl_seq * -_loop1_73_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // lambda_param_with_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop1_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); - NameDefaultPair* lambda_param_with_default_var; - while ( - (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default - ) - { - _res = lambda_param_with_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_73[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); - } - if (_n == 0 || p->error_indicator) { - PyMem_Free(_children); - p->level--; - return NULL; - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop0_74: lambda_param_maybe_default -static asdl_seq * -_loop0_74_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // lambda_param_maybe_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); - NameDefaultPair* lambda_param_maybe_default_var; - while ( - (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default - ) - { - _res = lambda_param_maybe_default_var; - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _loop1_75: lambda_param_maybe_default +// _loop1_75: lambda_param_with_default static asdl_seq * _loop1_75_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // lambda_param_with_default + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default")); + NameDefaultPair* lambda_param_with_default_var; + while ( + (lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default + ) + { + _res = lambda_param_with_default_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_75[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default")); + } + if (_n == 0 || p->error_indicator) { + PyMem_Free(_children); + p->level--; + return NULL; + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop0_76: lambda_param_maybe_default +static asdl_seq * +_loop0_76_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32404,7 +33036,7 @@ _loop1_75_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + D(fprintf(stderr, "%*c> _loop0_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); NameDefaultPair* lambda_param_maybe_default_var; while ( (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default @@ -32427,7 +33059,74 @@ _loop1_75_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_75[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_76[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _loop1_77: lambda_param_maybe_default +static asdl_seq * +_loop1_77_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // lambda_param_maybe_default + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop1_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default")); + NameDefaultPair* lambda_param_maybe_default_var; + while ( + (lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default + ) + { + _res = lambda_param_maybe_default_var; + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop1_77[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default")); } if (_n == 0 || p->error_indicator) { @@ -32449,9 +33148,9 @@ _loop1_75_rule(Parser *p) return _seq; } -// _loop0_76: fstring_format_spec +// _loop0_78: fstring_format_spec static asdl_seq * -_loop0_76_rule(Parser *p) +_loop0_78_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32476,7 +33175,7 @@ _loop0_76_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec")); expr_ty fstring_format_spec_var; while ( (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec @@ -32499,7 +33198,7 @@ _loop0_76_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_76[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32516,9 +33215,9 @@ _loop0_76_rule(Parser *p) return _seq; } -// _loop0_77: fstring_middle +// _loop0_79: fstring_middle static asdl_seq * -_loop0_77_rule(Parser *p) +_loop0_79_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32543,7 +33242,7 @@ _loop0_77_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); + D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle")); expr_ty fstring_middle_var; while ( (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle @@ -32566,7 +33265,7 @@ _loop0_77_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32583,9 +33282,9 @@ _loop0_77_rule(Parser *p) return _seq; } -// _loop0_78: tstring_format_spec +// _loop0_80: tstring_format_spec static asdl_seq * -_loop0_78_rule(Parser *p) +_loop0_80_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32610,7 +33309,7 @@ _loop0_78_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring_format_spec")); + D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring_format_spec")); expr_ty tstring_format_spec_var; while ( (tstring_format_spec_var = tstring_format_spec_rule(p)) // tstring_format_spec @@ -32633,7 +33332,7 @@ _loop0_78_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tstring_format_spec")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32650,9 +33349,9 @@ _loop0_78_rule(Parser *p) return _seq; } -// _loop0_79: tstring_middle +// _loop0_81: tstring_middle static asdl_seq * -_loop0_79_rule(Parser *p) +_loop0_81_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32677,7 +33376,7 @@ _loop0_79_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring_middle")); + D(fprintf(stderr, "%*c> _loop0_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring_middle")); expr_ty tstring_middle_var; while ( (tstring_middle_var = tstring_middle_rule(p)) // tstring_middle @@ -32700,7 +33399,7 @@ _loop0_79_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_81[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tstring_middle")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32717,9 +33416,9 @@ _loop0_79_rule(Parser *p) return _seq; } -// _loop1_80: (fstring | string) +// _loop1_82: (fstring | string) static asdl_seq * -_loop1_80_rule(Parser *p) +_loop1_82_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32744,13 +33443,13 @@ _loop1_80_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); - void *_tmp_154_var; + D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)")); + void *_tmp_156_var; while ( - (_tmp_154_var = _tmp_154_rule(p)) // fstring | string + (_tmp_156_var = _tmp_156_rule(p)) // fstring | string ) { - _res = _tmp_154_var; + _res = _tmp_156_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -32767,7 +33466,7 @@ _loop1_80_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_80[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)")); } if (_n == 0 || p->error_indicator) { @@ -32789,9 +33488,9 @@ _loop1_80_rule(Parser *p) return _seq; } -// _loop1_81: tstring +// _loop1_83: tstring static asdl_seq * -_loop1_81_rule(Parser *p) +_loop1_83_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32816,7 +33515,7 @@ _loop1_81_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring")); + D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tstring")); expr_ty tstring_var; while ( (tstring_var = tstring_rule(p)) // tstring @@ -32839,7 +33538,7 @@ _loop1_81_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_81[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tstring")); } if (_n == 0 || p->error_indicator) { @@ -32861,9 +33560,9 @@ _loop1_81_rule(Parser *p) return _seq; } -// _tmp_82: star_named_expression ',' star_named_expressions? +// _tmp_84: star_named_expression_sequence ',' star_named_expressions_sequence? static void * -_tmp_82_rule(Parser *p) +_tmp_84_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32874,24 +33573,24 @@ _tmp_82_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // star_named_expression ',' star_named_expressions? + { // star_named_expression_sequence ',' star_named_expressions_sequence? if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c> _tmp_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression_sequence ',' star_named_expressions_sequence?")); Token * _literal; expr_ty y; void *z; if ( - (y = star_named_expression_rule(p)) // star_named_expression + (y = star_named_expression_sequence_rule(p)) // star_named_expression_sequence && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions? + (z = star_named_expressions_sequence_rule(p), !p->error_indicator) // star_named_expressions_sequence? ) { - D(fprintf(stderr, "%*c+ _tmp_82[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c+ _tmp_84[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression_sequence ',' star_named_expressions_sequence?")); _res = _PyPegen_seq_insert_in_front ( p , y , z ); if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -32901,8 +33600,8 @@ _tmp_82_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_82[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?")); + D(fprintf(stderr, "%*c%s _tmp_84[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression_sequence ',' star_named_expressions_sequence?")); } _res = NULL; done: @@ -32910,9 +33609,9 @@ _tmp_82_rule(Parser *p) return _res; } -// _loop0_83: ',' double_starred_kvpair +// _loop0_85: ',' double_starred_kvpair static asdl_seq * -_loop0_83_rule(Parser *p) +_loop0_85_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32937,7 +33636,7 @@ _loop0_83_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); + D(fprintf(stderr, "%*c> _loop0_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair")); Token * _literal; KeyValuePair* elem; while ( @@ -32969,7 +33668,7 @@ _loop0_83_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_83[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_85[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -32986,9 +33685,9 @@ _loop0_83_rule(Parser *p) return _seq; } -// _gather_84: double_starred_kvpair _loop0_83 +// _gather_86: double_starred_kvpair _loop0_85 static asdl_seq * -_gather_84_rule(Parser *p) +_gather_86_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -32999,27 +33698,27 @@ _gather_84_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // double_starred_kvpair _loop0_83 + { // double_starred_kvpair _loop0_85 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_83")); + D(fprintf(stderr, "%*c> _gather_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_85")); KeyValuePair* elem; asdl_seq * seq; if ( (elem = double_starred_kvpair_rule(p)) // double_starred_kvpair && - (seq = _loop0_83_rule(p)) // _loop0_83 + (seq = _loop0_85_rule(p)) // _loop0_85 ) { - D(fprintf(stderr, "%*c+ _gather_84[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_83")); + D(fprintf(stderr, "%*c+ _gather_86[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_85")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_84[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_83")); + D(fprintf(stderr, "%*c%s _gather_86[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_85")); } _res = NULL; done: @@ -33027,9 +33726,9 @@ _gather_84_rule(Parser *p) return _res; } -// _loop1_85: for_if_clause +// _loop1_87: for_if_clause static asdl_seq * -_loop1_85_rule(Parser *p) +_loop1_87_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33054,7 +33753,7 @@ _loop1_85_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); + D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause")); comprehension_ty for_if_clause_var; while ( (for_if_clause_var = for_if_clause_rule(p)) // for_if_clause @@ -33077,7 +33776,7 @@ _loop1_85_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_85[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause")); } if (_n == 0 || p->error_indicator) { @@ -33099,9 +33798,9 @@ _loop1_85_rule(Parser *p) return _seq; } -// _loop0_86: ('if' disjunction) +// _loop0_88: ('if' disjunction) static asdl_seq * -_loop0_86_rule(Parser *p) +_loop0_88_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33126,13 +33825,13 @@ _loop0_86_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); - void *_tmp_164_var; + D(fprintf(stderr, "%*c> _loop0_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)")); + void *_tmp_166_var; while ( - (_tmp_164_var = _tmp_164_rule(p)) // 'if' disjunction + (_tmp_166_var = _tmp_166_rule(p)) // 'if' disjunction ) { - _res = _tmp_164_var; + _res = _tmp_166_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33149,7 +33848,7 @@ _loop0_86_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_88[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33166,9 +33865,9 @@ _loop0_86_rule(Parser *p) return _seq; } -// _tmp_87: assignment_expression | expression !':=' +// _tmp_89: assignment_expression | expression !':=' | starred_expression static void * -_tmp_87_rule(Parser *p) +_tmp_89_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33184,18 +33883,18 @@ _tmp_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); expr_ty assignment_expression_var; if ( (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression ) { - D(fprintf(stderr, "%*c+ _tmp_87[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); _res = assignment_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); } { // expression !':=' @@ -33203,7 +33902,7 @@ _tmp_87_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression @@ -33211,23 +33910,42 @@ _tmp_87_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_87[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); _res = expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_87[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); } + { // starred_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + expr_ty starred_expression_var; + if ( + (starred_expression_var = starred_expression_rule(p)) // starred_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + _res = starred_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); + } _res = NULL; done: p->level--; return _res; } -// _loop0_88: ',' (starred_expression | (assignment_expression | expression !':=') !'=') +// _loop0_90: ',' (starred_expression | (assignment_expression | expression !':=') !'=') static asdl_seq * -_loop0_88_rule(Parser *p) +_loop0_90_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33252,13 +33970,13 @@ _loop0_88_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); + D(fprintf(stderr, "%*c> _loop0_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_165_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_167_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' ) { _res = elem; @@ -33284,7 +34002,7 @@ _loop0_88_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_88[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_90[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33301,10 +34019,10 @@ _loop0_88_rule(Parser *p) return _seq; } -// _gather_89: -// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_88 +// _gather_91: +// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_90 static asdl_seq * -_gather_89_rule(Parser *p) +_gather_91_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33315,27 +34033,27 @@ _gather_89_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_88 + { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_90 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_88")); + D(fprintf(stderr, "%*c> _gather_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_90")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_165_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' + (elem = _tmp_167_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'=' && - (seq = _loop0_88_rule(p)) // _loop0_88 + (seq = _loop0_90_rule(p)) // _loop0_90 ) { - D(fprintf(stderr, "%*c+ _gather_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_88")); + D(fprintf(stderr, "%*c+ _gather_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_90")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_89[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_88")); + D(fprintf(stderr, "%*c%s _gather_91[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_90")); } _res = NULL; done: @@ -33343,9 +34061,9 @@ _gather_89_rule(Parser *p) return _res; } -// _tmp_90: ',' kwargs +// _tmp_92: ',' kwargs static void * -_tmp_90_rule(Parser *p) +_tmp_92_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33361,7 +34079,7 @@ _tmp_90_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs")); Token * _literal; asdl_seq* k; if ( @@ -33370,7 +34088,7 @@ _tmp_90_rule(Parser *p) (k = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); + D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs")); _res = k; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -33380,7 +34098,7 @@ _tmp_90_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_90[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs")); } _res = NULL; @@ -33389,9 +34107,9 @@ _tmp_90_rule(Parser *p) return _res; } -// _loop0_91: ',' kwarg_or_starred +// _loop0_93: ',' kwarg_or_starred static asdl_seq * -_loop0_91_rule(Parser *p) +_loop0_93_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33416,7 +34134,7 @@ _loop0_91_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); + D(fprintf(stderr, "%*c> _loop0_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred")); Token * _literal; KeywordOrStarred* elem; while ( @@ -33448,124 +34166,124 @@ _loop0_91_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_91[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _gather_92: kwarg_or_starred _loop0_91 -static asdl_seq * -_gather_92_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - asdl_seq * _res = NULL; - int _mark = p->mark; - { // kwarg_or_starred _loop0_91 - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _gather_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_91")); - KeywordOrStarred* elem; - asdl_seq * seq; - if ( - (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred - && - (seq = _loop0_91_rule(p)) // _loop0_91 - ) - { - D(fprintf(stderr, "%*c+ _gather_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_91")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_92[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_91")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_93: ',' kwarg_or_double_starred -static asdl_seq * -_loop0_93_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // ',' kwarg_or_double_starred - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); - Token * _literal; - KeywordOrStarred* elem; - while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred - ) - { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - p->level--; - return NULL; - } - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_93[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_94: kwarg_or_starred _loop0_93 +static asdl_seq * +_gather_94_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // kwarg_or_starred _loop0_93 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_93")); + KeywordOrStarred* elem; + asdl_seq * seq; + if ( + (elem = kwarg_or_starred_rule(p)) // kwarg_or_starred + && + (seq = _loop0_93_rule(p)) // _loop0_93 + ) + { + D(fprintf(stderr, "%*c+ _gather_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_93")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_94[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_93")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_95: ',' kwarg_or_double_starred +static asdl_seq * +_loop0_95_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' kwarg_or_double_starred + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred")); + Token * _literal; + KeywordOrStarred* elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_95[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33582,9 +34300,9 @@ _loop0_93_rule(Parser *p) return _seq; } -// _gather_94: kwarg_or_double_starred _loop0_93 +// _gather_96: kwarg_or_double_starred _loop0_95 static asdl_seq * -_gather_94_rule(Parser *p) +_gather_96_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33595,27 +34313,27 @@ _gather_94_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // kwarg_or_double_starred _loop0_93 + { // kwarg_or_double_starred _loop0_95 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_93")); + D(fprintf(stderr, "%*c> _gather_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_95")); KeywordOrStarred* elem; asdl_seq * seq; if ( (elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred && - (seq = _loop0_93_rule(p)) // _loop0_93 + (seq = _loop0_95_rule(p)) // _loop0_95 ) { - D(fprintf(stderr, "%*c+ _gather_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_93")); + D(fprintf(stderr, "%*c+ _gather_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_95")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_94[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_93")); + D(fprintf(stderr, "%*c%s _gather_96[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_95")); } _res = NULL; done: @@ -33623,9 +34341,9 @@ _gather_94_rule(Parser *p) return _res; } -// _loop0_95: (',' star_target) +// _loop0_97: (',' star_target) static asdl_seq * -_loop0_95_rule(Parser *p) +_loop0_97_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33650,13 +34368,13 @@ _loop0_95_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_166_var; + D(fprintf(stderr, "%*c> _loop0_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_168_var; while ( - (_tmp_166_var = _tmp_166_rule(p)) // ',' star_target + (_tmp_168_var = _tmp_168_rule(p)) // ',' star_target ) { - _res = _tmp_166_var; + _res = _tmp_168_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33673,7 +34391,7 @@ _loop0_95_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_95[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_97[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33690,9 +34408,9 @@ _loop0_95_rule(Parser *p) return _seq; } -// _loop0_96: ',' star_target +// _loop0_98: ',' star_target static asdl_seq * -_loop0_96_rule(Parser *p) +_loop0_98_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33717,7 +34435,7 @@ _loop0_96_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty elem; while ( @@ -33749,7 +34467,7 @@ _loop0_96_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_96[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -33766,9 +34484,9 @@ _loop0_96_rule(Parser *p) return _seq; } -// _gather_97: star_target _loop0_96 +// _gather_99: star_target _loop0_98 static asdl_seq * -_gather_97_rule(Parser *p) +_gather_99_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33779,27 +34497,27 @@ _gather_97_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // star_target _loop0_96 + { // star_target _loop0_98 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_96")); + D(fprintf(stderr, "%*c> _gather_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_98")); expr_ty elem; asdl_seq * seq; if ( (elem = star_target_rule(p)) // star_target && - (seq = _loop0_96_rule(p)) // _loop0_96 + (seq = _loop0_98_rule(p)) // _loop0_98 ) { - D(fprintf(stderr, "%*c+ _gather_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_96")); + D(fprintf(stderr, "%*c+ _gather_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_98")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_97[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_96")); + D(fprintf(stderr, "%*c%s _gather_99[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_98")); } _res = NULL; done: @@ -33807,9 +34525,9 @@ _gather_97_rule(Parser *p) return _res; } -// _loop1_98: (',' star_target) +// _loop1_100: (',' star_target) static asdl_seq * -_loop1_98_rule(Parser *p) +_loop1_100_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33834,13 +34552,13 @@ _loop1_98_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); - void *_tmp_166_var; + D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)")); + void *_tmp_168_var; while ( - (_tmp_166_var = _tmp_166_rule(p)) // ',' star_target + (_tmp_168_var = _tmp_168_rule(p)) // ',' star_target ) { - _res = _tmp_166_var; + _res = _tmp_168_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -33857,7 +34575,7 @@ _loop1_98_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_98[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_100[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)")); } if (_n == 0 || p->error_indicator) { @@ -33879,9 +34597,9 @@ _loop1_98_rule(Parser *p) return _seq; } -// _tmp_99: !'*' star_target +// _tmp_101: !'*' star_target static void * -_tmp_99_rule(Parser *p) +_tmp_101_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33897,7 +34615,7 @@ _tmp_99_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c> _tmp_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); expr_ty star_target_var; if ( _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*' @@ -33905,12 +34623,12 @@ _tmp_99_rule(Parser *p) (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_99[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); + D(fprintf(stderr, "%*c+ _tmp_101[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target")); _res = star_target_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_99[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_101[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target")); } _res = NULL; @@ -33919,9 +34637,9 @@ _tmp_99_rule(Parser *p) return _res; } -// _loop0_100: ',' del_target +// _loop0_102: ',' del_target static asdl_seq * -_loop0_100_rule(Parser *p) +_loop0_102_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -33946,7 +34664,7 @@ _loop0_100_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); + D(fprintf(stderr, "%*c> _loop0_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target")); Token * _literal; expr_ty elem; while ( @@ -33978,125 +34696,8 @@ _loop0_100_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_100[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); - } - asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); - if (!_seq) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); - PyMem_Free(_children); - p->level--; - return _seq; -} - -// _gather_101: del_target _loop0_100 -static asdl_seq * -_gather_101_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - asdl_seq * _res = NULL; - int _mark = p->mark; - { // del_target _loop0_100 - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _gather_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_100")); - expr_ty elem; - asdl_seq * seq; - if ( - (elem = del_target_rule(p)) // del_target - && - (seq = _loop0_100_rule(p)) // _loop0_100 - ) - { - D(fprintf(stderr, "%*c+ _gather_101[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_100")); - _res = _PyPegen_seq_insert_in_front(p, elem, seq); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_101[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_100")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_102: ',' expression -static asdl_seq * -_loop0_102_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void *_res = NULL; - int _mark = p->mark; - void **_children = PyMem_Malloc(sizeof(void *)); - if (!_children) { - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - Py_ssize_t _children_capacity = 1; - Py_ssize_t _n = 0; - { // ',' expression - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _loop0_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); - Token * _literal; - expr_ty elem; - while ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - && - (elem = expression_rule(p)) // expression - ) - { - _res = elem; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - PyMem_Free(_children); - p->level--; - return NULL; - } - if (_n == _children_capacity) { - _children_capacity *= 2; - void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); - if (!_new_children) { - PyMem_Free(_children); - p->error_indicator = 1; - PyErr_NoMemory(); - p->level--; - return NULL; - } - _children = _new_children; - } - _children[_n++] = _res; - _mark = p->mark; - } - p->mark = _mark; D(fprintf(stderr, "%*c%s _loop0_102[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); if (!_seq) { @@ -34112,7 +34713,7 @@ _loop0_102_rule(Parser *p) return _seq; } -// _gather_103: expression _loop0_102 +// _gather_103: del_target _loop0_102 static asdl_seq * _gather_103_rule(Parser *p) { @@ -34125,27 +34726,27 @@ _gather_103_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // expression _loop0_102 + { // del_target _loop0_102 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_102")); + D(fprintf(stderr, "%*c> _gather_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_102")); expr_ty elem; asdl_seq * seq; if ( - (elem = expression_rule(p)) // expression + (elem = del_target_rule(p)) // del_target && (seq = _loop0_102_rule(p)) // _loop0_102 ) { - D(fprintf(stderr, "%*c+ _gather_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_102")); + D(fprintf(stderr, "%*c+ _gather_103[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_102")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _gather_103[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_102")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_102")); } _res = NULL; done: @@ -34153,109 +34754,9 @@ _gather_103_rule(Parser *p) return _res; } -// _tmp_104: NEWLINE INDENT -static void * -_tmp_104_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // NEWLINE INDENT - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); - Token * indent_var; - Token * newline_var; - if ( - (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' - && - (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' - ) - { - D(fprintf(stderr, "%*c+ _tmp_104[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); - _res = _PyPegen_dummy_name(p, newline_var, indent_var); - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_104[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_105: -// | (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) -// | kwargs -static void * -_tmp_105_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - void *_tmp_167_var; - if ( - (_tmp_167_var = _tmp_167_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs - ) - { - D(fprintf(stderr, "%*c+ _tmp_105[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - _res = _tmp_167_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_105[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); - } - { // kwargs - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwargs")); - asdl_seq* kwargs_var; - if ( - (kwargs_var = kwargs_rule(p)) // kwargs - ) - { - D(fprintf(stderr, "%*c+ _tmp_105[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwargs")); - _res = kwargs_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_105[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwargs")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _loop0_106: ',' (starred_expression !'=') +// _loop0_104: ',' expression static asdl_seq * -_loop0_106_rule(Parser *p) +_loop0_104_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34275,18 +34776,18 @@ _loop0_106_rule(Parser *p) } Py_ssize_t _children_capacity = 1; Py_ssize_t _n = 0; - { // ',' (starred_expression !'=') + { // ',' expression if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression !'=')")); + D(fprintf(stderr, "%*c> _loop0_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression")); Token * _literal; - void *elem; + expr_ty elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_168_rule(p)) // starred_expression !'=' + (elem = expression_rule(p)) // expression ) { _res = elem; @@ -34312,7 +34813,224 @@ _loop0_106_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_106[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_104[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression")); + } + asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); + if (!_seq) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + for (Py_ssize_t i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]); + PyMem_Free(_children); + p->level--; + return _seq; +} + +// _gather_105: expression _loop0_104 +static asdl_seq * +_gather_105_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + asdl_seq * _res = NULL; + int _mark = p->mark; + { // expression _loop0_104 + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _gather_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_104")); + expr_ty elem; + asdl_seq * seq; + if ( + (elem = expression_rule(p)) // expression + && + (seq = _loop0_104_rule(p)) // _loop0_104 + ) + { + D(fprintf(stderr, "%*c+ _gather_105[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_104")); + _res = _PyPegen_seq_insert_in_front(p, elem, seq); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _gather_105[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_104")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_106: NEWLINE INDENT +static void * +_tmp_106_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // NEWLINE INDENT + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + Token * indent_var; + Token * newline_var; + if ( + (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' + && + (indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT' + ) + { + D(fprintf(stderr, "%*c+ _tmp_106[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT")); + _res = _PyPegen_dummy_name(p, newline_var, indent_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_106[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_107: +// | (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) +// | kwargs +static void * +_tmp_107_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // (','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs) + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + void *_tmp_169_var; + if ( + (_tmp_169_var = _tmp_169_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + _res = _tmp_169_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_107[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs)")); + } + { // kwargs + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwargs")); + asdl_seq* kwargs_var; + if ( + (kwargs_var = kwargs_rule(p)) // kwargs + ) + { + D(fprintf(stderr, "%*c+ _tmp_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwargs")); + _res = kwargs_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_107[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwargs")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _loop0_108: ',' (starred_expression !'=') +static asdl_seq * +_loop0_108_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void *_res = NULL; + int _mark = p->mark; + void **_children = PyMem_Malloc(sizeof(void *)); + if (!_children) { + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + Py_ssize_t _children_capacity = 1; + Py_ssize_t _n = 0; + { // ',' (starred_expression !'=') + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _loop0_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression !'=')")); + Token * _literal; + void *elem; + while ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + && + (elem = _tmp_170_rule(p)) // starred_expression !'=' + ) + { + _res = elem; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + PyMem_Free(_children); + p->level--; + return NULL; + } + if (_n == _children_capacity) { + _children_capacity *= 2; + void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); + if (!_new_children) { + PyMem_Free(_children); + p->error_indicator = 1; + PyErr_NoMemory(); + p->level--; + return NULL; + } + _children = _new_children; + } + _children[_n++] = _res; + _mark = p->mark; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _loop0_108[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression !'=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -34329,9 +35047,9 @@ _loop0_106_rule(Parser *p) return _seq; } -// _gather_107: (starred_expression !'=') _loop0_106 +// _gather_109: (starred_expression !'=') _loop0_108 static asdl_seq * -_gather_107_rule(Parser *p) +_gather_109_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34342,27 +35060,27 @@ _gather_107_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (starred_expression !'=') _loop0_106 + { // (starred_expression !'=') _loop0_108 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_106")); + D(fprintf(stderr, "%*c> _gather_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_108")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_168_rule(p)) // starred_expression !'=' + (elem = _tmp_170_rule(p)) // starred_expression !'=' && - (seq = _loop0_106_rule(p)) // _loop0_106 + (seq = _loop0_108_rule(p)) // _loop0_108 ) { - D(fprintf(stderr, "%*c+ _gather_107[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_106")); + D(fprintf(stderr, "%*c+ _gather_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression !'=') _loop0_108")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_107[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression !'=') _loop0_106")); + D(fprintf(stderr, "%*c%s _gather_109[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression !'=') _loop0_108")); } _res = NULL; done: @@ -34370,9 +35088,9 @@ _gather_107_rule(Parser *p) return _res; } -// _tmp_108: args | expression for_if_clauses +// _tmp_110: args | expression for_if_clauses static void * -_tmp_108_rule(Parser *p) +_tmp_110_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34388,18 +35106,18 @@ _tmp_108_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args")); expr_ty args_var; if ( (args_var = args_rule(p)) // args ) { - D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); + D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args")); _res = args_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args")); } { // expression for_if_clauses @@ -34407,7 +35125,7 @@ _tmp_108_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); expr_ty expression_var; asdl_comprehension_seq* for_if_clauses_var; if ( @@ -34416,12 +35134,12 @@ _tmp_108_rule(Parser *p) (for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses ) { - D(fprintf(stderr, "%*c+ _tmp_108[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); + D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses")); _res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_108[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses")); } _res = NULL; @@ -34430,9 +35148,9 @@ _tmp_108_rule(Parser *p) return _res; } -// _tmp_109: args ',' +// _tmp_111: args ',' static void * -_tmp_109_rule(Parser *p) +_tmp_111_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34448,7 +35166,7 @@ _tmp_109_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','")); Token * _literal; expr_ty args_var; if ( @@ -34457,12 +35175,12 @@ _tmp_109_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_109[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); + D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','")); _res = _PyPegen_dummy_name(p, args_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_109[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','")); } _res = NULL; @@ -34471,9 +35189,9 @@ _tmp_109_rule(Parser *p) return _res; } -// _tmp_110: ',' | ')' +// _tmp_112: ',' | ')' static void * -_tmp_110_rule(Parser *p) +_tmp_112_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34489,18 +35207,18 @@ _tmp_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -34508,18 +35226,18 @@ _tmp_110_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_110[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_110[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } _res = NULL; @@ -34528,9 +35246,9 @@ _tmp_110_rule(Parser *p) return _res; } -// _tmp_111: 'True' | 'False' | 'None' +// _tmp_113: 'True' | 'False' | 'None' static void * -_tmp_111_rule(Parser *p) +_tmp_113_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34546,18 +35264,18 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='True' + (_keyword = _PyPegen_expect_token(p, 627)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'False' @@ -34565,18 +35283,18 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 625)) // token='False' + (_keyword = _PyPegen_expect_token(p, 629)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } { // 'None' @@ -34584,18 +35302,18 @@ _tmp_111_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 624)) // token='None' + (_keyword = _PyPegen_expect_token(p, 628)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_111[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_111[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } _res = NULL; @@ -34604,9 +35322,9 @@ _tmp_111_rule(Parser *p) return _res; } -// _tmp_112: NAME '=' +// _tmp_114: NAME '=' static void * -_tmp_112_rule(Parser *p) +_tmp_114_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34622,7 +35340,7 @@ _tmp_112_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='")); Token * _literal; expr_ty name_var; if ( @@ -34631,12 +35349,12 @@ _tmp_112_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); + D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='")); _res = _PyPegen_dummy_name(p, name_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='")); } _res = NULL; @@ -34645,9 +35363,9 @@ _tmp_112_rule(Parser *p) return _res; } -// _loop1_113: (!STRING expression_without_invalid) +// _loop1_115: (!STRING expression_without_invalid) static asdl_seq * -_loop1_113_rule(Parser *p) +_loop1_115_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34672,13 +35390,13 @@ _loop1_113_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop1_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(!STRING expression_without_invalid)")); - void *_tmp_169_var; + D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(!STRING expression_without_invalid)")); + void *_tmp_171_var; while ( - (_tmp_169_var = _tmp_169_rule(p)) // !STRING expression_without_invalid + (_tmp_171_var = _tmp_171_rule(p)) // !STRING expression_without_invalid ) { - _res = _tmp_169_var; + _res = _tmp_171_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -34695,7 +35413,7 @@ _loop1_113_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop1_113[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop1_115[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(!STRING expression_without_invalid)")); } if (_n == 0 || p->error_indicator) { @@ -34717,9 +35435,9 @@ _loop1_113_rule(Parser *p) return _seq; } -// _tmp_114: NAME STRING | SOFT_KEYWORD +// _tmp_116: NAME STRING | SOFT_KEYWORD static void * -_tmp_114_rule(Parser *p) +_tmp_116_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34735,7 +35453,7 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING")); expr_ty name_var; expr_ty string_var; if ( @@ -34744,12 +35462,12 @@ _tmp_114_rule(Parser *p) (string_var = _PyPegen_string_token(p)) // STRING ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); + D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING")); _res = _PyPegen_dummy_name(p, name_var, string_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING")); } { // SOFT_KEYWORD @@ -34757,18 +35475,18 @@ _tmp_114_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); expr_ty soft_keyword_var; if ( (soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD ) { - D(fprintf(stderr, "%*c+ _tmp_114[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); + D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD")); _res = soft_keyword_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_114[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD")); } _res = NULL; @@ -34777,9 +35495,9 @@ _tmp_114_rule(Parser *p) return _res; } -// _tmp_115: 'else' | ':' +// _tmp_117: 'else' | ':' static void * -_tmp_115_rule(Parser *p) +_tmp_117_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34795,18 +35513,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 695)) // token='else' + (_keyword = _PyPegen_expect_token(p, 699)) // token='else' ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); + D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'")); } { // ':' @@ -34814,18 +35532,18 @@ _tmp_115_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_115[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_115[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -34834,9 +35552,9 @@ _tmp_115_rule(Parser *p) return _res; } -// _tmp_116: pass_stmt | break_stmt | continue_stmt +// _tmp_118: pass_stmt | break_stmt | continue_stmt static void * -_tmp_116_rule(Parser *p) +_tmp_118_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34852,18 +35570,18 @@ _tmp_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pass_stmt")); + D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pass_stmt")); stmt_ty pass_stmt_var; if ( (pass_stmt_var = pass_stmt_rule(p)) // pass_stmt ) { - D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pass_stmt")); + D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pass_stmt")); _res = pass_stmt_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pass_stmt")); } { // break_stmt @@ -34871,18 +35589,18 @@ _tmp_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "break_stmt")); + D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "break_stmt")); stmt_ty break_stmt_var; if ( (break_stmt_var = break_stmt_rule(p)) // break_stmt ) { - D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "break_stmt")); + D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "break_stmt")); _res = break_stmt_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "break_stmt")); } { // continue_stmt @@ -34890,18 +35608,18 @@ _tmp_116_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "continue_stmt")); + D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "continue_stmt")); stmt_ty continue_stmt_var; if ( (continue_stmt_var = continue_stmt_rule(p)) // continue_stmt ) { - D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "continue_stmt")); + D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "continue_stmt")); _res = continue_stmt_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "continue_stmt")); } _res = NULL; @@ -34910,9 +35628,9 @@ _tmp_116_rule(Parser *p) return _res; } -// _tmp_117: '=' | ':=' +// _tmp_119: '=' | ':=' static void * -_tmp_117_rule(Parser *p) +_tmp_119_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34928,18 +35646,18 @@ _tmp_117_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); } { // ':=' @@ -34947,18 +35665,18 @@ _tmp_117_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c> _tmp_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 53)) // token=':=' ) { - D(fprintf(stderr, "%*c+ _tmp_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); + D(fprintf(stderr, "%*c+ _tmp_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_117[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_119[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='")); } _res = NULL; @@ -34967,9 +35685,9 @@ _tmp_117_rule(Parser *p) return _res; } -// _tmp_118: list | tuple | genexp | 'True' | 'None' | 'False' +// _tmp_120: list | tuple | genexp | 'True' | 'None' | 'False' static void * -_tmp_118_rule(Parser *p) +_tmp_120_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -34985,18 +35703,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list")); expr_ty list_var; if ( (list_var = list_rule(p)) // list ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list")); _res = list_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list")); } { // tuple @@ -35004,18 +35722,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple")); expr_ty tuple_var; if ( (tuple_var = tuple_rule(p)) // tuple ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple")); _res = tuple_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple")); } { // genexp @@ -35023,18 +35741,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp")); expr_ty genexp_var; if ( (genexp_var = genexp_rule(p)) // genexp ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp")); _res = genexp_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp")); } { // 'True' @@ -35042,18 +35760,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 623)) // token='True' + (_keyword = _PyPegen_expect_token(p, 627)) // token='True' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'")); } { // 'None' @@ -35061,18 +35779,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 624)) // token='None' + (_keyword = _PyPegen_expect_token(p, 628)) // token='None' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'")); } { // 'False' @@ -35080,18 +35798,18 @@ _tmp_118_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c> _tmp_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 625)) // token='False' + (_keyword = _PyPegen_expect_token(p, 629)) // token='False' ) { - D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); + D(fprintf(stderr, "%*c+ _tmp_120[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_120[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'")); } _res = NULL; @@ -35100,9 +35818,9 @@ _tmp_118_rule(Parser *p) return _res; } -// _loop0_119: star_named_expressions +// _loop0_121: star_named_expressions static asdl_seq * -_loop0_119_rule(Parser *p) +_loop0_121_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35127,7 +35845,7 @@ _loop0_119_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); + D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions")); asdl_expr_seq* star_named_expressions_var; while ( (star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions @@ -35150,7 +35868,7 @@ _loop0_119_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_119[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_121[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35167,9 +35885,9 @@ _loop0_119_rule(Parser *p) return _seq; } -// _loop0_120: (star_targets '=') +// _loop0_122: (star_targets '=') static asdl_seq * -_loop0_120_rule(Parser *p) +_loop0_122_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35194,13 +35912,13 @@ _loop0_120_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); - void *_tmp_157_var; + D(fprintf(stderr, "%*c> _loop0_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')")); + void *_tmp_159_var; while ( - (_tmp_157_var = _tmp_157_rule(p)) // star_targets '=' + (_tmp_159_var = _tmp_159_rule(p)) // star_targets '=' ) { - _res = _tmp_157_var; + _res = _tmp_159_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -35217,7 +35935,7 @@ _loop0_120_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_120[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_122[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35234,142 +35952,66 @@ _loop0_120_rule(Parser *p) return _seq; } -// _tmp_121: '[' | '(' | '{' -static void * -_tmp_121_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '[' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 9)) // token='[' - ) - { - D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); - } - { // '(' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 7)) // token='(' - ) - { - D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('")); - } - { // '{' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 25)) // token='{' - ) - { - D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_122: '[' | '{' -static void * -_tmp_122_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '[' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 9)) // token='[' - ) - { - D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); - } - { // '{' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 25)) // token='{' - ) - { - D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_123: slash_no_default | slash_with_default +// _tmp_123: '[' | '{' static void * _tmp_123_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '[' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 9)) // token='[' + ) + { + D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['")); + } + { // '{' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 25)) // token='{' + ) + { + D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_124: slash_no_default | slash_with_default +static void * +_tmp_124_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35385,18 +36027,18 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default")); asdl_arg_seq* slash_no_default_var; if ( (slash_no_default_var = slash_no_default_rule(p)) // slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default")); _res = slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default")); } { // slash_with_default @@ -35404,18 +36046,18 @@ _tmp_123_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default")); SlashWithDefault* slash_with_default_var; if ( (slash_with_default_var = slash_with_default_rule(p)) // slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default")); _res = slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_123[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default")); } _res = NULL; @@ -35424,64 +36066,7 @@ _tmp_123_rule(Parser *p) return _res; } -// _tmp_124: ',' | param_no_default -static void * -_tmp_124_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // ',' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - ) - { - D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); - } - { // param_no_default - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); - arg_ty param_no_default_var; - if ( - (param_no_default_var = param_no_default_rule(p)) // param_no_default - ) - { - D(fprintf(stderr, "%*c+ _tmp_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); - _res = param_no_default_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_124[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_125: ')' | ',' +// _tmp_125: ',' | param_no_default static void * _tmp_125_rule(Parser *p) { @@ -35494,25 +36079,6 @@ _tmp_125_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // ')' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 8)) // token=')' - ) - { - D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); - } { // ',' if (p->error_indicator) { p->level--; @@ -35532,13 +36098,32 @@ _tmp_125_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } + { // param_no_default + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + arg_ty param_no_default_var; + if ( + (param_no_default_var = param_no_default_rule(p)) // param_no_default + ) + { + D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + _res = param_no_default_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); + } _res = NULL; done: p->level--; return _res; } -// _tmp_126: ')' | ',' (')' | '**') +// _tmp_126: ')' | ',' static void * _tmp_126_rule(Parser *p) { @@ -35570,26 +36155,83 @@ _tmp_126_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } + { // ',' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + ) + { + D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_127: ')' | ',' (')' | '**') +static void * +_tmp_127_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ')' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 8)) // token=')' + ) + { + D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); + } { // ',' (')' | '**') if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); Token * _literal; - void *_tmp_170_var; + void *_tmp_172_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_170_var = _tmp_170_rule(p)) // ')' | '**' + (_tmp_172_var = _tmp_172_rule(p)) // ')' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_170_var); + D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_172_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_126[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')")); } _res = NULL; @@ -35598,9 +36240,9 @@ _tmp_126_rule(Parser *p) return _res; } -// _tmp_127: param_no_default | ',' +// _tmp_128: param_no_default | ',' static void * -_tmp_127_rule(Parser *p) +_tmp_128_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35616,18 +36258,18 @@ _tmp_127_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default")); arg_ty param_no_default_var; if ( (param_no_default_var = param_no_default_rule(p)) // param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default")); _res = param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default")); } { // ',' @@ -35635,18 +36277,18 @@ _tmp_127_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_127[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_127[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -35655,9 +36297,9 @@ _tmp_127_rule(Parser *p) return _res; } -// _tmp_128: '*' | '**' | '/' +// _tmp_129: '*' | '**' | '/' static void * -_tmp_128_rule(Parser *p) +_tmp_129_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35673,18 +36315,18 @@ _tmp_128_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '**' @@ -35692,18 +36334,18 @@ _tmp_128_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } { // '/' @@ -35711,18 +36353,18 @@ _tmp_128_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_128[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } _res = NULL; @@ -35731,9 +36373,9 @@ _tmp_128_rule(Parser *p) return _res; } -// _tmp_129: lambda_slash_no_default | lambda_slash_with_default +// _tmp_130: lambda_slash_no_default | lambda_slash_with_default static void * -_tmp_129_rule(Parser *p) +_tmp_130_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35749,18 +36391,18 @@ _tmp_129_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); asdl_arg_seq* lambda_slash_no_default_var; if ( (lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default")); _res = lambda_slash_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default")); } { // lambda_slash_with_default @@ -35768,18 +36410,18 @@ _tmp_129_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c> _tmp_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); SlashWithDefault* lambda_slash_with_default_var; if ( (lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default ) { - D(fprintf(stderr, "%*c+ _tmp_129[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); + D(fprintf(stderr, "%*c+ _tmp_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default")); _res = lambda_slash_with_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_129[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_130[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default")); } _res = NULL; @@ -35788,9 +36430,9 @@ _tmp_129_rule(Parser *p) return _res; } -// _loop0_130: ',' lambda_param +// _loop0_131: ',' lambda_param static asdl_seq * -_loop0_130_rule(Parser *p) +_loop0_131_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35815,7 +36457,7 @@ _loop0_130_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); + D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param")); Token * _literal; arg_ty elem; while ( @@ -35847,7 +36489,7 @@ _loop0_130_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_130[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -35864,9 +36506,9 @@ _loop0_130_rule(Parser *p) return _seq; } -// _gather_131: lambda_param _loop0_130 +// _gather_132: lambda_param _loop0_131 static asdl_seq * -_gather_131_rule(Parser *p) +_gather_132_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35877,27 +36519,27 @@ _gather_131_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // lambda_param _loop0_130 + { // lambda_param _loop0_131 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_130")); + D(fprintf(stderr, "%*c> _gather_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_131")); arg_ty elem; asdl_seq * seq; if ( (elem = lambda_param_rule(p)) // lambda_param && - (seq = _loop0_130_rule(p)) // _loop0_130 + (seq = _loop0_131_rule(p)) // _loop0_131 ) { - D(fprintf(stderr, "%*c+ _gather_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_130")); + D(fprintf(stderr, "%*c+ _gather_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_131")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_131[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_130")); + D(fprintf(stderr, "%*c%s _gather_132[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_131")); } _res = NULL; done: @@ -35905,9 +36547,9 @@ _gather_131_rule(Parser *p) return _res; } -// _tmp_132: ',' | lambda_param_no_default +// _tmp_133: ',' | lambda_param_no_default static void * -_tmp_132_rule(Parser *p) +_tmp_133_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35923,18 +36565,18 @@ _tmp_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // lambda_param_no_default @@ -35942,18 +36584,18 @@ _tmp_132_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_132[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } _res = NULL; @@ -35962,9 +36604,9 @@ _tmp_132_rule(Parser *p) return _res; } -// _tmp_133: ':' | ',' (':' | '**') +// _tmp_134: ':' | ',' (':' | '**') static void * -_tmp_133_rule(Parser *p) +_tmp_134_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -35980,18 +36622,18 @@ _tmp_133_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // ',' (':' | '**') @@ -35999,21 +36641,21 @@ _tmp_133_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); Token * _literal; - void *_tmp_171_var; + void *_tmp_173_var; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (_tmp_171_var = _tmp_171_rule(p)) // ':' | '**' + (_tmp_173_var = _tmp_173_rule(p)) // ':' | '**' ) { - D(fprintf(stderr, "%*c+ _tmp_133[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); - _res = _PyPegen_dummy_name(p, _literal, _tmp_171_var); + D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')")); + _res = _PyPegen_dummy_name(p, _literal, _tmp_173_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_133[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')")); } _res = NULL; @@ -36022,9 +36664,9 @@ _tmp_133_rule(Parser *p) return _res; } -// _tmp_134: lambda_param_no_default | ',' +// _tmp_135: lambda_param_no_default | ',' static void * -_tmp_134_rule(Parser *p) +_tmp_135_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36040,18 +36682,18 @@ _tmp_134_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); arg_ty lambda_param_no_default_var; if ( (lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default")); _res = lambda_param_no_default_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default")); } { // ',' @@ -36059,18 +36701,18 @@ _tmp_134_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } _res = NULL; @@ -36079,9 +36721,9 @@ _tmp_134_rule(Parser *p) return _res; } -// _tmp_135: bitwise_or ((',' bitwise_or))* ','? +// _tmp_136: bitwise_or ((',' bitwise_or))* ','? static void * -_tmp_135_rule(Parser *p) +_tmp_136_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36097,25 +36739,25 @@ _tmp_135_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - asdl_seq * _loop0_172_var; + D(fprintf(stderr, "%*c> _tmp_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); + asdl_seq * _loop0_174_var; void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty bitwise_or_var; if ( (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or && - (_loop0_172_var = _loop0_172_rule(p)) // ((',' bitwise_or))* + (_loop0_174_var = _loop0_174_rule(p)) // ((',' bitwise_or))* && (_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','? ) { - D(fprintf(stderr, "%*c+ _tmp_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); - _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_172_var, _opt_var); + D(fprintf(stderr, "%*c+ _tmp_136[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); + _res = _PyPegen_dummy_name(p, bitwise_or_var, _loop0_174_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_135[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_136[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "bitwise_or ((',' bitwise_or))* ','?")); } _res = NULL; @@ -36124,9 +36766,9 @@ _tmp_135_rule(Parser *p) return _res; } -// _loop0_136: ',' dotted_name +// _loop0_137: ',' dotted_name static asdl_seq * -_loop0_136_rule(Parser *p) +_loop0_137_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36151,7 +36793,7 @@ _loop0_136_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); + D(fprintf(stderr, "%*c> _loop0_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_name")); Token * _literal; expr_ty elem; while ( @@ -36183,7 +36825,7 @@ _loop0_136_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_136[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_137[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_name")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36200,9 +36842,9 @@ _loop0_136_rule(Parser *p) return _seq; } -// _gather_137: dotted_name _loop0_136 +// _gather_138: dotted_name _loop0_137 static asdl_seq * -_gather_137_rule(Parser *p) +_gather_138_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36213,27 +36855,27 @@ _gather_137_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // dotted_name _loop0_136 + { // dotted_name _loop0_137 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_136")); + D(fprintf(stderr, "%*c> _gather_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_137")); expr_ty elem; asdl_seq * seq; if ( (elem = dotted_name_rule(p)) // dotted_name && - (seq = _loop0_136_rule(p)) // _loop0_136 + (seq = _loop0_137_rule(p)) // _loop0_137 ) { - D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_136")); + D(fprintf(stderr, "%*c+ _gather_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name _loop0_137")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_136")); + D(fprintf(stderr, "%*c%s _gather_138[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_name _loop0_137")); } _res = NULL; done: @@ -36241,9 +36883,9 @@ _gather_137_rule(Parser *p) return _res; } -// _tmp_138: NAME (',' | ')' | ';' | NEWLINE) +// _tmp_139: NAME (',' | ')' | ';' | NEWLINE) static void * -_tmp_138_rule(Parser *p) +_tmp_139_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36259,21 +36901,21 @@ _tmp_138_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); - void *_tmp_173_var; + D(fprintf(stderr, "%*c> _tmp_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); + void *_tmp_175_var; expr_ty name_var; if ( (name_var = _PyPegen_name_token(p)) // NAME && - (_tmp_173_var = _tmp_173_rule(p)) // ',' | ')' | ';' | NEWLINE + (_tmp_175_var = _tmp_175_rule(p)) // ',' | ')' | ';' | NEWLINE ) { - D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); - _res = _PyPegen_dummy_name(p, name_var, _tmp_173_var); + D(fprintf(stderr, "%*c+ _tmp_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); + _res = _PyPegen_dummy_name(p, name_var, _tmp_175_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_139[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME (',' | ')' | ';' | NEWLINE)")); } _res = NULL; @@ -36282,9 +36924,9 @@ _tmp_138_rule(Parser *p) return _res; } -// _loop0_139: ',' (expression ['as' star_target]) +// _loop0_140: ',' (expression ['as' star_target]) static asdl_seq * -_loop0_139_rule(Parser *p) +_loop0_140_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36309,13 +36951,13 @@ _loop0_139_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_174_rule(p)) // expression ['as' star_target] + (elem = _tmp_176_rule(p)) // expression ['as' star_target] ) { _res = elem; @@ -36341,7 +36983,7 @@ _loop0_139_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_139[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36358,9 +37000,9 @@ _loop0_139_rule(Parser *p) return _seq; } -// _gather_140: (expression ['as' star_target]) _loop0_139 +// _gather_141: (expression ['as' star_target]) _loop0_140 static asdl_seq * -_gather_140_rule(Parser *p) +_gather_141_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36371,27 +37013,27 @@ _gather_140_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expression ['as' star_target]) _loop0_139 + { // (expression ['as' star_target]) _loop0_140 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_139")); + D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_140")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_174_rule(p)) // expression ['as' star_target] + (elem = _tmp_176_rule(p)) // expression ['as' star_target] && - (seq = _loop0_139_rule(p)) // _loop0_139 + (seq = _loop0_140_rule(p)) // _loop0_140 ) { - D(fprintf(stderr, "%*c+ _gather_140[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_139")); + D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_140")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_140[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_139")); + D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_140")); } _res = NULL; done: @@ -36399,9 +37041,9 @@ _gather_140_rule(Parser *p) return _res; } -// _loop0_141: ',' (expressions ['as' star_target]) +// _loop0_142: ',' (expressions ['as' star_target]) static asdl_seq * -_loop0_141_rule(Parser *p) +_loop0_142_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36426,13 +37068,13 @@ _loop0_141_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); + D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])")); Token * _literal; void *elem; while ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' && - (elem = _tmp_175_rule(p)) // expressions ['as' star_target] + (elem = _tmp_177_rule(p)) // expressions ['as' star_target] ) { _res = elem; @@ -36458,7 +37100,7 @@ _loop0_141_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_141[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36475,9 +37117,9 @@ _loop0_141_rule(Parser *p) return _seq; } -// _gather_142: (expressions ['as' star_target]) _loop0_141 +// _gather_143: (expressions ['as' star_target]) _loop0_142 static asdl_seq * -_gather_142_rule(Parser *p) +_gather_143_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36488,27 +37130,27 @@ _gather_142_rule(Parser *p) } asdl_seq * _res = NULL; int _mark = p->mark; - { // (expressions ['as' star_target]) _loop0_141 + { // (expressions ['as' star_target]) _loop0_142 if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _gather_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_141")); + D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_142")); void *elem; asdl_seq * seq; if ( - (elem = _tmp_175_rule(p)) // expressions ['as' star_target] + (elem = _tmp_177_rule(p)) // expressions ['as' star_target] && - (seq = _loop0_141_rule(p)) // _loop0_141 + (seq = _loop0_142_rule(p)) // _loop0_142 ) { - D(fprintf(stderr, "%*c+ _gather_142[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_141")); + D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_142")); _res = _PyPegen_seq_insert_in_front(p, elem, seq); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _gather_142[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_141")); + D(fprintf(stderr, "%*c%s _gather_143[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_142")); } _res = NULL; done: @@ -36516,9 +37158,9 @@ _gather_142_rule(Parser *p) return _res; } -// _tmp_143: 'except' | 'finally' +// _tmp_144: 'except' | 'finally' static void * -_tmp_143_rule(Parser *p) +_tmp_144_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36534,18 +37176,18 @@ _tmp_143_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 686)) // token='except' + (_keyword = _PyPegen_expect_token(p, 690)) // token='except' ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'")); } { // 'finally' @@ -36553,18 +37195,18 @@ _tmp_143_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c> _tmp_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'")); Token * _keyword; if ( - (_keyword = _PyPegen_expect_token(p, 682)) // token='finally' + (_keyword = _PyPegen_expect_token(p, 686)) // token='finally' ) { - D(fprintf(stderr, "%*c+ _tmp_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); + D(fprintf(stderr, "%*c+ _tmp_144[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'")); _res = _keyword; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_143[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_144[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'")); } _res = NULL; @@ -36573,9 +37215,9 @@ _tmp_143_rule(Parser *p) return _res; } -// _loop0_144: block +// _loop0_145: block static asdl_seq * -_loop0_144_rule(Parser *p) +_loop0_145_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36600,7 +37242,7 @@ _loop0_144_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); + D(fprintf(stderr, "%*c> _loop0_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block")); asdl_stmt_seq* block_var; while ( (block_var = block_rule(p)) // block @@ -36623,7 +37265,7 @@ _loop0_144_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_144[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_145[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -36640,9 +37282,9 @@ _loop0_144_rule(Parser *p) return _seq; } -// _tmp_145: expression ['as' NAME] +// _tmp_146: expression ['as' NAME] static void * -_tmp_145_rule(Parser *p) +_tmp_146_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36658,7 +37300,7 @@ _tmp_145_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; @@ -36668,12 +37310,12 @@ _tmp_145_rule(Parser *p) (_opt_var = _tmp_21_rule(p), !p->error_indicator) // ['as' NAME] ) { - D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); + D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]")); } _res = NULL; @@ -36682,9 +37324,9 @@ _tmp_145_rule(Parser *p) return _res; } -// _tmp_146: NEWLINE | ':' +// _tmp_147: NEWLINE | ':' static void * -_tmp_146_rule(Parser *p) +_tmp_147_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36700,18 +37342,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } { // ':' @@ -36719,18 +37361,18 @@ _tmp_146_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } _res = NULL; @@ -36739,9 +37381,9 @@ _tmp_146_rule(Parser *p) return _res; } -// _tmp_147: items_pattern ',' +// _tmp_148: items_pattern ',' static void * -_tmp_147_rule(Parser *p) +_tmp_148_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36757,7 +37399,7 @@ _tmp_147_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); + D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); Token * _literal; asdl_seq* items_pattern_var; if ( @@ -36766,12 +37408,12 @@ _tmp_147_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); + D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "items_pattern ','")); _res = _PyPegen_dummy_name(p, items_pattern_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "items_pattern ','")); } _res = NULL; @@ -36780,9 +37422,9 @@ _tmp_147_rule(Parser *p) return _res; } -// _tmp_148: positional_patterns ',' +// _tmp_149: positional_patterns ',' static void * -_tmp_148_rule(Parser *p) +_tmp_149_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -36798,7 +37440,7 @@ _tmp_148_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); Token * _literal; asdl_pattern_seq* positional_patterns_var; if ( @@ -36807,12 +37449,12 @@ _tmp_148_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); + D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','")); _res = _PyPegen_dummy_name(p, positional_patterns_var, _literal); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','")); } _res = NULL; @@ -36821,64 +37463,7 @@ _tmp_148_rule(Parser *p) return _res; } -// _tmp_149: '}' | ',' -static void * -_tmp_149_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // '}' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 26)) // token='}' - ) - { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); - } - { // ',' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 12)) // token=',' - ) - { - D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_150: '=' | '!' | ':' | '}' +// _tmp_150: invalid_kvpair | invalid_kvpair_unpacking static void * _tmp_150_rule(Parser *p) { @@ -36891,81 +37476,43 @@ _tmp_150_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '=' + if (p->call_invalid_rules) { // invalid_kvpair if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); - Token * _literal; + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_kvpair")); + void *invalid_kvpair_var; if ( - (_literal = _PyPegen_expect_token(p, 22)) // token='=' + (invalid_kvpair_var = invalid_kvpair_rule(p)) // invalid_kvpair ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); - _res = _literal; + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_kvpair")); + _res = invalid_kvpair_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_kvpair")); } - { // '!' + if (p->call_invalid_rules) { // invalid_kvpair_unpacking if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); - Token * _literal; + D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_kvpair_unpacking")); + void *invalid_kvpair_unpacking_var; if ( - (_literal = _PyPegen_expect_token(p, 54)) // token='!' + (invalid_kvpair_unpacking_var = invalid_kvpair_unpacking_rule(p)) // invalid_kvpair_unpacking ) { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); - _res = _literal; + D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_kvpair_unpacking")); + _res = invalid_kvpair_unpacking_var; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); - } - { // ':' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 11)) // token=':' - ) - { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); - } - { // '}' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 26)) // token='}' - ) - { - D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_kvpair_unpacking")); } _res = NULL; done: @@ -36973,7 +37520,7 @@ _tmp_150_rule(Parser *p) return _res; } -// _tmp_151: '!' | ':' | '}' +// _tmp_151: '}' | ',' static void * _tmp_151_rule(Parser *p) { @@ -36986,44 +37533,6 @@ _tmp_151_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '!' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 54)) // token='!' - ) - { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); - } - { // ':' - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); - Token * _literal; - if ( - (_literal = _PyPegen_expect_token(p, 11)) // token=':' - ) - { - D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); - _res = _literal; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); - } { // '}' if (p->error_indicator) { p->level--; @@ -37043,13 +37552,32 @@ _tmp_151_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } + { // ',' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 12)) // token=',' + ) + { + D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); + } _res = NULL; done: p->level--; return _res; } -// _tmp_152: '!' NAME +// _tmp_152: '=' | '!' | ':' | '}' static void * _tmp_152_rule(Parser *p) { @@ -37062,27 +37590,81 @@ _tmp_152_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; - { // '!' NAME + { // '=' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='")); Token * _literal; - expr_ty name_var; if ( - (_literal = _PyPegen_expect_token(p, 54)) // token='!' - && - (name_var = _PyPegen_name_token(p)) // NAME + (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); - _res = _PyPegen_dummy_name(p, _literal, name_var); + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='")); + _res = _literal; goto done; } p->mark = _mark; D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='")); + } + { // '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); + } + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); } _res = NULL; done: @@ -37090,7 +37672,7 @@ _tmp_152_rule(Parser *p) return _res; } -// _tmp_153: ':' | '}' +// _tmp_153: '!' | ':' | '}' static void * _tmp_153_rule(Parser *p) { @@ -37103,6 +37685,25 @@ _tmp_153_rule(Parser *p) } void * _res = NULL; int _mark = p->mark; + { // '!' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + ) + { + D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'")); + } { // ':' if (p->error_indicator) { p->level--; @@ -37147,9 +37748,107 @@ _tmp_153_rule(Parser *p) return _res; } -// _tmp_154: fstring | string +// _tmp_154: '!' NAME static void * _tmp_154_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // '!' NAME + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + Token * _literal; + expr_ty name_var; + if ( + (_literal = _PyPegen_expect_token(p, 54)) // token='!' + && + (name_var = _PyPegen_name_token(p)) // NAME + ) + { + D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME")); + _res = _PyPegen_dummy_name(p, _literal, name_var); + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_155: ':' | '}' +static void * +_tmp_155_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // ':' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 11)) // token=':' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); + } + { // '}' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'")); + Token * _literal; + if ( + (_literal = _PyPegen_expect_token(p, 26)) // token='}' + ) + { + D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'")); + _res = _literal; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_156: fstring | string +static void * +_tmp_156_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37165,18 +37864,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring")); expr_ty fstring_var; if ( (fstring_var = fstring_rule(p)) // fstring ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring")); _res = fstring_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring")); } { // string @@ -37184,18 +37883,18 @@ _tmp_154_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string")); expr_ty string_var; if ( (string_var = string_rule(p)) // string ) { - D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); + D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string")); _res = string_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string")); } _res = NULL; @@ -37204,9 +37903,9 @@ _tmp_154_rule(Parser *p) return _res; } -// _tmp_155: '+' | '-' | '*' | '/' | '%' | '//' | '@' +// _tmp_157: '+' | '-' | '*' | '/' | '%' | '//' | '@' static void * -_tmp_155_rule(Parser *p) +_tmp_157_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37222,18 +37921,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -37241,18 +37940,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } { // '*' @@ -37260,18 +37959,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 16)) // token='*' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'")); } { // '/' @@ -37279,18 +37978,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 17)) // token='/' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'")); } { // '%' @@ -37298,18 +37997,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'%'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 24)) // token='%' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'%'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'%'")); } { // '//' @@ -37317,18 +38016,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'//'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 47)) // token='//' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'//'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'//'")); } { // '@' @@ -37336,18 +38035,18 @@ _tmp_155_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 49)) // token='@' ) { - D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); + D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'")); } _res = NULL; @@ -37356,9 +38055,9 @@ _tmp_155_rule(Parser *p) return _res; } -// _tmp_156: '+' | '-' | '~' +// _tmp_158: '+' | '-' | '~' static void * -_tmp_156_rule(Parser *p) +_tmp_158_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37374,18 +38073,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 14)) // token='+' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'")); } { // '-' @@ -37393,18 +38092,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 15)) // token='-' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'")); } { // '~' @@ -37412,18 +38111,18 @@ _tmp_156_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'~'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 31)) // token='~' ) { - D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); + D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'~'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'~'")); } _res = NULL; @@ -37432,9 +38131,9 @@ _tmp_156_rule(Parser *p) return _res; } -// _tmp_157: star_targets '=' +// _tmp_159: star_targets '=' static void * -_tmp_157_rule(Parser *p) +_tmp_159_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37450,7 +38149,7 @@ _tmp_157_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='")); Token * _literal; expr_ty z; if ( @@ -37459,7 +38158,7 @@ _tmp_157_rule(Parser *p) (_literal = _PyPegen_expect_token(p, 22)) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); + D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='")); _res = z; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37469,7 +38168,7 @@ _tmp_157_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='")); } _res = NULL; @@ -37478,9 +38177,9 @@ _tmp_157_rule(Parser *p) return _res; } -// _tmp_158: '.' | '...' +// _tmp_160: '.' | '...' static void * -_tmp_158_rule(Parser *p) +_tmp_160_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37496,18 +38195,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 23)) // token='.' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'")); } { // '...' @@ -37515,18 +38214,18 @@ _tmp_158_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 52)) // token='...' ) { - D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); + D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'")); } _res = NULL; @@ -37535,9 +38234,9 @@ _tmp_158_rule(Parser *p) return _res; } -// _tmp_159: '@' named_expression NEWLINE +// _tmp_161: '@' named_expression NEWLINE static void * -_tmp_159_rule(Parser *p) +_tmp_161_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37553,7 +38252,7 @@ _tmp_159_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); Token * _literal; expr_ty f; Token * newline_var; @@ -37565,7 +38264,7 @@ _tmp_159_rule(Parser *p) (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE")); _res = f; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37575,7 +38274,7 @@ _tmp_159_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE")); } _res = NULL; @@ -37584,9 +38283,9 @@ _tmp_159_rule(Parser *p) return _res; } -// _tmp_160: ',' star_expression +// _tmp_162: ',' star_expression static void * -_tmp_160_rule(Parser *p) +_tmp_162_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37602,7 +38301,7 @@ _tmp_160_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression")); Token * _literal; expr_ty c; if ( @@ -37611,7 +38310,7 @@ _tmp_160_rule(Parser *p) (c = star_expression_rule(p)) // star_expression ) { - D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); + D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37621,7 +38320,7 @@ _tmp_160_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression")); } _res = NULL; @@ -37630,9 +38329,9 @@ _tmp_160_rule(Parser *p) return _res; } -// _tmp_161: 'or' conjunction +// _tmp_163: 'or' conjunction static void * -_tmp_161_rule(Parser *p) +_tmp_163_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37648,7 +38347,7 @@ _tmp_161_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); Token * _keyword; expr_ty c; if ( @@ -37657,7 +38356,7 @@ _tmp_161_rule(Parser *p) (c = conjunction_rule(p)) // conjunction ) { - D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); + D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37667,7 +38366,7 @@ _tmp_161_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction")); } _res = NULL; @@ -37676,9 +38375,9 @@ _tmp_161_rule(Parser *p) return _res; } -// _tmp_162: 'and' inversion +// _tmp_164: 'and' inversion static void * -_tmp_162_rule(Parser *p) +_tmp_164_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37694,7 +38393,7 @@ _tmp_162_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion")); Token * _keyword; expr_ty c; if ( @@ -37703,7 +38402,7 @@ _tmp_162_rule(Parser *p) (c = inversion_rule(p)) // inversion ) { - D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); + D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37713,7 +38412,7 @@ _tmp_162_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion")); } _res = NULL; @@ -37722,9 +38421,9 @@ _tmp_162_rule(Parser *p) return _res; } -// _tmp_163: slice | starred_expression +// _tmp_165: slice | starred_expression static void * -_tmp_163_rule(Parser *p) +_tmp_165_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37740,104 +38439,20 @@ _tmp_163_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice")); expr_ty slice_var; if ( (slice_var = slice_rule(p)) // slice ) { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); + D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice")); _res = slice_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice")); } - { // starred_expression - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); - expr_ty starred_expression_var; - if ( - (starred_expression_var = starred_expression_rule(p)) // starred_expression - ) - { - D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); - _res = starred_expression_var; - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_164: 'if' disjunction -static void * -_tmp_164_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; - { // 'if' disjunction - if (p->error_indicator) { - p->level--; - return NULL; - } - D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); - Token * _keyword; - expr_ty z; - if ( - (_keyword = _PyPegen_expect_token(p, 691)) // token='if' - && - (z = disjunction_rule(p)) // disjunction - ) - { - D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); - _res = z; - if (_res == NULL && PyErr_Occurred()) { - p->error_indicator = 1; - p->level--; - return NULL; - } - goto done; - } - p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ', - p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); - } - _res = NULL; - done: - p->level--; - return _res; -} - -// _tmp_165: starred_expression | (assignment_expression | expression !':=') !'=' -static void * -_tmp_165_rule(Parser *p) -{ - if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { - _Pypegen_stack_overflow(p); - } - if (p->error_indicator) { - p->level--; - return NULL; - } - void * _res = NULL; - int _mark = p->mark; { // starred_expression if (p->error_indicator) { p->level--; @@ -37857,25 +38472,109 @@ _tmp_165_rule(Parser *p) D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_166: 'if' disjunction +static void * +_tmp_166_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // 'if' disjunction + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + Token * _keyword; + expr_ty z; + if ( + (_keyword = _PyPegen_expect_token(p, 695)) // token='if' + && + (z = disjunction_rule(p)) // disjunction + ) + { + D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction")); + _res = z; + if (_res == NULL && PyErr_Occurred()) { + p->error_indicator = 1; + p->level--; + return NULL; + } + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_167: starred_expression | (assignment_expression | expression !':=') !'=' +static void * +_tmp_167_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // starred_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression")); + expr_ty starred_expression_var; + if ( + (starred_expression_var = starred_expression_rule(p)) // starred_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression")); + _res = starred_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression")); + } { // (assignment_expression | expression !':=') !'=' if (p->error_indicator) { p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - void *_tmp_87_var; + D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + void *_tmp_178_var; if ( - (_tmp_87_var = _tmp_87_rule(p)) // assignment_expression | expression !':=' + (_tmp_178_var = _tmp_178_rule(p)) // assignment_expression | expression !':=' && _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); - _res = _tmp_87_var; + D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='")); + _res = _tmp_178_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='")); } _res = NULL; @@ -37884,9 +38583,9 @@ _tmp_165_rule(Parser *p) return _res; } -// _tmp_166: ',' star_target +// _tmp_168: ',' star_target static void * -_tmp_166_rule(Parser *p) +_tmp_168_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37902,7 +38601,7 @@ _tmp_166_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target")); Token * _literal; expr_ty c; if ( @@ -37911,7 +38610,7 @@ _tmp_166_rule(Parser *p) (c = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); + D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target")); _res = c; if (_res == NULL && PyErr_Occurred()) { p->error_indicator = 1; @@ -37921,7 +38620,7 @@ _tmp_166_rule(Parser *p) goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target")); } _res = NULL; @@ -37930,10 +38629,10 @@ _tmp_166_rule(Parser *p) return _res; } -// _tmp_167: +// _tmp_169: // | ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs static void * -_tmp_167_rule(Parser *p) +_tmp_169_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37949,24 +38648,24 @@ _tmp_167_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); - asdl_seq * _gather_89_var; + D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + asdl_seq * _gather_91_var; Token * _literal; asdl_seq* kwargs_var; if ( - (_gather_89_var = _gather_89_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ + (_gather_91_var = _gather_91_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+ && (_literal = _PyPegen_expect_token(p, 12)) // token=',' && (kwargs_var = kwargs_rule(p)) // kwargs ) { - D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); - _res = _PyPegen_dummy_name(p, _gather_89_var, _literal, kwargs_var); + D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); + _res = _PyPegen_dummy_name(p, _gather_91_var, _literal, kwargs_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ ',' kwargs")); } _res = NULL; @@ -37975,9 +38674,9 @@ _tmp_167_rule(Parser *p) return _res; } -// _tmp_168: starred_expression !'=' +// _tmp_170: starred_expression !'=' static void * -_tmp_168_rule(Parser *p) +_tmp_170_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -37993,7 +38692,7 @@ _tmp_168_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); expr_ty starred_expression_var; if ( (starred_expression_var = starred_expression_rule(p)) // starred_expression @@ -38001,12 +38700,12 @@ _tmp_168_rule(Parser *p) _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='=' ) { - D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); + D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression !'='")); _res = starred_expression_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression !'='")); } _res = NULL; @@ -38015,9 +38714,9 @@ _tmp_168_rule(Parser *p) return _res; } -// _tmp_169: !STRING expression_without_invalid +// _tmp_171: !STRING expression_without_invalid static void * -_tmp_169_rule(Parser *p) +_tmp_171_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38033,7 +38732,7 @@ _tmp_169_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); + D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); expr_ty expression_without_invalid_var; if ( _PyPegen_lookahead(0, _PyPegen_string_token, p) @@ -38041,12 +38740,12 @@ _tmp_169_rule(Parser *p) (expression_without_invalid_var = expression_without_invalid_rule(p)) // expression_without_invalid ) { - D(fprintf(stderr, "%*c+ _tmp_169[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); + D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!STRING expression_without_invalid")); _res = expression_without_invalid_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_169[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!STRING expression_without_invalid")); } _res = NULL; @@ -38055,9 +38754,9 @@ _tmp_169_rule(Parser *p) return _res; } -// _tmp_170: ')' | '**' +// _tmp_172: ')' | '**' static void * -_tmp_170_rule(Parser *p) +_tmp_172_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38073,18 +38772,18 @@ _tmp_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // '**' @@ -38092,18 +38791,18 @@ _tmp_170_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_172[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_172[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -38112,9 +38811,9 @@ _tmp_170_rule(Parser *p) return _res; } -// _tmp_171: ':' | '**' +// _tmp_173: ':' | '**' static void * -_tmp_171_rule(Parser *p) +_tmp_173_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38130,18 +38829,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 11)) // token=':' ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'")); } { // '**' @@ -38149,18 +38848,18 @@ _tmp_171_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 35)) // token='**' ) { - D(fprintf(stderr, "%*c+ _tmp_171[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); + D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_171[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'")); } _res = NULL; @@ -38169,9 +38868,9 @@ _tmp_171_rule(Parser *p) return _res; } -// _loop0_172: (',' bitwise_or) +// _loop0_174: (',' bitwise_or) static asdl_seq * -_loop0_172_rule(Parser *p) +_loop0_174_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38196,13 +38895,13 @@ _loop0_172_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _loop0_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); - void *_tmp_176_var; + D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' bitwise_or)")); + void *_tmp_179_var; while ( - (_tmp_176_var = _tmp_176_rule(p)) // ',' bitwise_or + (_tmp_179_var = _tmp_179_rule(p)) // ',' bitwise_or ) { - _res = _tmp_176_var; + _res = _tmp_179_var; if (_n == _children_capacity) { _children_capacity *= 2; void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *)); @@ -38219,7 +38918,7 @@ _loop0_172_rule(Parser *p) _mark = p->mark; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _loop0_172[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' bitwise_or)")); } asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena); @@ -38236,9 +38935,9 @@ _loop0_172_rule(Parser *p) return _seq; } -// _tmp_173: ',' | ')' | ';' | NEWLINE +// _tmp_175: ',' | ')' | ';' | NEWLINE static void * -_tmp_173_rule(Parser *p) +_tmp_175_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38254,18 +38953,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 12)) // token=',' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','")); } { // ')' @@ -38273,18 +38972,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 8)) // token=')' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'")); } { // ';' @@ -38292,18 +38991,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'")); Token * _literal; if ( (_literal = _PyPegen_expect_token(p, 13)) // token=';' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'")); _res = _literal; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'")); } { // NEWLINE @@ -38311,18 +39010,18 @@ _tmp_173_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE")); Token * newline_var; if ( (newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE' ) { - D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); + D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE")); _res = newline_var; goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE")); } _res = NULL; @@ -38331,9 +39030,9 @@ _tmp_173_rule(Parser *p) return _res; } -// _tmp_174: expression ['as' star_target] +// _tmp_176: expression ['as' star_target] static void * -_tmp_174_rule(Parser *p) +_tmp_176_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38349,22 +39048,22 @@ _tmp_174_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expression_var; if ( (expression_var = expression_rule(p)) // expression && - (_opt_var = _tmp_177_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_180_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]")); _res = _PyPegen_dummy_name(p, expression_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]")); } _res = NULL; @@ -38373,9 +39072,9 @@ _tmp_174_rule(Parser *p) return _res; } -// _tmp_175: expressions ['as' star_target] +// _tmp_177: expressions ['as' star_target] static void * -_tmp_175_rule(Parser *p) +_tmp_177_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38391,22 +39090,22 @@ _tmp_175_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); void *_opt_var; UNUSED(_opt_var); // Silence compiler warnings expr_ty expressions_var; if ( (expressions_var = expressions_rule(p)) // expressions && - (_opt_var = _tmp_177_rule(p), !p->error_indicator) // ['as' star_target] + (_opt_var = _tmp_180_rule(p), !p->error_indicator) // ['as' star_target] ) { - D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); + D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]")); _res = _PyPegen_dummy_name(p, expressions_var, _opt_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]")); } _res = NULL; @@ -38415,9 +39114,68 @@ _tmp_175_rule(Parser *p) return _res; } -// _tmp_176: ',' bitwise_or +// _tmp_178: assignment_expression | expression !':=' static void * -_tmp_176_rule(Parser *p) +_tmp_178_rule(Parser *p) +{ + if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { + _Pypegen_stack_overflow(p); + } + if (p->error_indicator) { + p->level--; + return NULL; + } + void * _res = NULL; + int _mark = p->mark; + { // assignment_expression + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + expr_ty assignment_expression_var; + if ( + (assignment_expression_var = assignment_expression_rule(p)) // assignment_expression + ) + { + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression")); + _res = assignment_expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression")); + } + { // expression !':=' + if (p->error_indicator) { + p->level--; + return NULL; + } + D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='")); + expr_ty expression_var; + if ( + (expression_var = expression_rule(p)) // expression + && + _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':=' + ) + { + D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='")); + _res = expression_var; + goto done; + } + p->mark = _mark; + D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ', + p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='")); + } + _res = NULL; + done: + p->level--; + return _res; +} + +// _tmp_179: ',' bitwise_or +static void * +_tmp_179_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38433,7 +39191,7 @@ _tmp_176_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); Token * _literal; expr_ty bitwise_or_var; if ( @@ -38442,12 +39200,12 @@ _tmp_176_rule(Parser *p) (bitwise_or_var = bitwise_or_rule(p)) // bitwise_or ) { - D(fprintf(stderr, "%*c+ _tmp_176[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); + D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' bitwise_or")); _res = _PyPegen_dummy_name(p, _literal, bitwise_or_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_176[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' bitwise_or")); } _res = NULL; @@ -38456,9 +39214,9 @@ _tmp_176_rule(Parser *p) return _res; } -// _tmp_177: 'as' star_target +// _tmp_180: 'as' star_target static void * -_tmp_177_rule(Parser *p) +_tmp_180_rule(Parser *p) { if (p->level++ == MAXSTACK || _Py_ReachedRecursionLimitWithMargin(PyThreadState_Get(), 1)) { _Pypegen_stack_overflow(p); @@ -38474,21 +39232,21 @@ _tmp_177_rule(Parser *p) p->level--; return NULL; } - D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target")); Token * _keyword; expr_ty star_target_var; if ( - (_keyword = _PyPegen_expect_token(p, 689)) // token='as' + (_keyword = _PyPegen_expect_token(p, 693)) // token='as' && (star_target_var = star_target_rule(p)) // star_target ) { - D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); + D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target")); _res = _PyPegen_dummy_name(p, _keyword, star_target_var); goto done; } p->mark = _mark; - D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ', + D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ', p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target")); } _res = NULL; diff --git a/Python/Python-ast.c b/Python/Python-ast.c index 1cc88dc179e..577adb825b0 100644 --- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -2864,7 +2864,12 @@ add_ast_annotations(struct ast_state *state) } { PyObject *type = state->expr_type; - Py_INCREF(type); + type = _Py_union_type_or(type, Py_None); + cond = type != NULL; + if (!cond) { + Py_DECREF(DictComp_annotations); + return 0; + } cond = PyDict_SetItemString(DictComp_annotations, "value", type) == 0; Py_DECREF(type); if (!cond) { @@ -6392,7 +6397,7 @@ init_types(void *arg) " | Set(expr* elts)\n" " | ListComp(expr elt, comprehension* generators)\n" " | SetComp(expr elt, comprehension* generators)\n" - " | DictComp(expr key, expr value, comprehension* generators)\n" + " | DictComp(expr key, expr? value, comprehension* generators)\n" " | GeneratorExp(expr elt, comprehension* generators)\n" " | Await(expr value)\n" " | Yield(expr? value)\n" @@ -6460,8 +6465,10 @@ init_types(void *arg) if (!state->SetComp_type) return -1; state->DictComp_type = make_type(state, "DictComp", state->expr_type, DictComp_fields, 3, - "DictComp(expr key, expr value, comprehension* generators)"); + "DictComp(expr key, expr? value, comprehension* generators)"); if (!state->DictComp_type) return -1; + if (PyObject_SetAttr(state->DictComp_type, state->value, Py_None) == -1) + return -1; state->GeneratorExp_type = make_type(state, "GeneratorExp", state->expr_type, GeneratorExp_fields, 2, @@ -8007,11 +8014,6 @@ _PyAST_DictComp(expr_ty key, expr_ty value, asdl_comprehension_seq * "field 'key' is required for DictComp"); return NULL; } - if (!value) { - PyErr_SetString(PyExc_ValueError, - "field 'value' is required for DictComp"); - return NULL; - } p = (expr_ty)_PyArena_Malloc(arena, sizeof(*p)); if (!p) return NULL; @@ -14526,9 +14528,9 @@ obj2ast_expr(struct ast_state *state, PyObject* obj, expr_ty* out, PyArena* if (PyObject_GetOptionalAttr(obj, state->value, &tmp) < 0) { return -1; } - if (tmp == NULL) { - PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from DictComp"); - return -1; + if (tmp == NULL || tmp == Py_None) { + Py_CLEAR(tmp); + value = NULL; } else { int res; diff --git a/Python/ast.c b/Python/ast.c index e01dd0de51e..4cfa2ff559a 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -305,8 +305,10 @@ validate_expr(expr_ty exp, expr_context_ty ctx) #undef COMP case DictComp_kind: ret = validate_comprehension(exp->v.DictComp.generators) && - validate_expr(exp->v.DictComp.key, Load) && - validate_expr(exp->v.DictComp.value, Load); + validate_expr(exp->v.DictComp.key, Load); + if (ret && exp->v.DictComp.value != NULL){ + ret = validate_expr(exp->v.DictComp.value, Load); + } break; case Yield_kind: ret = !exp->v.Yield.value || validate_expr(exp->v.Yield.value, Load); diff --git a/Python/ast_preprocess.c b/Python/ast_preprocess.c index d45435257cc..54dec3dfe04 100644 --- a/Python/ast_preprocess.c +++ b/Python/ast_preprocess.c @@ -557,7 +557,9 @@ astfold_expr(expr_ty node_, PyArena *ctx_, _PyASTPreprocessState *state) break; case DictComp_kind: CALL(astfold_expr, expr_ty, node_->v.DictComp.key); - CALL(astfold_expr, expr_ty, node_->v.DictComp.value); + if (node_->v.DictComp.value != NULL){ + CALL(astfold_expr, expr_ty, node_->v.DictComp.value); + } CALL_SEQ(astfold_comprehension, comprehension, node_->v.DictComp.generators); break; case GeneratorExp_kind: diff --git a/Python/codegen.c b/Python/codegen.c index 478fbec1cba..5227312b4f7 100644 --- a/Python/codegen.c +++ b/Python/codegen.c @@ -4522,28 +4522,63 @@ codegen_sync_comprehension_generator(compiler *c, location loc, /* comprehension specific code */ switch (type) { case COMP_GENEXP: - VISIT(c, expr, elt); - ADDOP_YIELD(c, elt_loc); - ADDOP(c, elt_loc, POP_TOP); + if (elt->kind == Starred_kind) { + NEW_JUMP_TARGET_LABEL(c, unpack_start); + NEW_JUMP_TARGET_LABEL(c, unpack_end); + VISIT(c, expr, elt->v.Starred.value); + ADDOP(c, elt_loc, GET_ITER); + USE_LABEL(c, unpack_start); + ADDOP_JUMP(c, elt_loc, FOR_ITER, unpack_end); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); + ADDOP_JUMP(c, NO_LOCATION, JUMP, unpack_start); + USE_LABEL(c, unpack_end); + ADDOP(c, NO_LOCATION, END_FOR); + ADDOP(c, NO_LOCATION, POP_ITER); + } + else { + VISIT(c, expr, elt); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); + } break; case COMP_LISTCOMP: - VISIT(c, expr, elt); - ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); + if (elt->kind == Starred_kind) { + VISIT(c, expr, elt->v.Starred.value); + ADDOP_I(c, elt_loc, LIST_EXTEND, depth + 1); + } + else { + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); + } break; case COMP_SETCOMP: - VISIT(c, expr, elt); - ADDOP_I(c, elt_loc, SET_ADD, depth + 1); + if (elt->kind == Starred_kind) { + VISIT(c, expr, elt->v.Starred.value); + ADDOP_I(c, elt_loc, SET_UPDATE, depth + 1); + } + else { + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, SET_ADD, depth + 1); + } break; case COMP_DICTCOMP: - /* With '{k: v}', k is evaluated before v, so we do - the same. */ - VISIT(c, expr, elt); - VISIT(c, expr, val); - elt_loc = LOCATION(elt->lineno, - val->end_lineno, - elt->col_offset, - val->end_col_offset); - ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); + if (val == NULL) { + /* unpacking (**) case */ + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, DICT_UPDATE, depth+1); + } + else { + /* With '{k: v}', k is evaluated before v, so we do + the same. */ + VISIT(c, expr, elt); + VISIT(c, expr, val); + elt_loc = LOCATION(elt->lineno, + val->end_lineno, + elt->col_offset, + val->end_col_offset); + ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); + } break; default: return ERROR; @@ -4629,28 +4664,63 @@ codegen_async_comprehension_generator(compiler *c, location loc, /* comprehension specific code */ switch (type) { case COMP_GENEXP: - VISIT(c, expr, elt); - ADDOP_YIELD(c, elt_loc); - ADDOP(c, elt_loc, POP_TOP); + if (elt->kind == Starred_kind) { + NEW_JUMP_TARGET_LABEL(c, unpack_start); + NEW_JUMP_TARGET_LABEL(c, unpack_end); + VISIT(c, expr, elt->v.Starred.value); + ADDOP(c, elt_loc, GET_ITER); + USE_LABEL(c, unpack_start); + ADDOP_JUMP(c, elt_loc, FOR_ITER, unpack_end); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); + ADDOP_JUMP(c, NO_LOCATION, JUMP, unpack_start); + USE_LABEL(c, unpack_end); + ADDOP(c, NO_LOCATION, END_FOR); + ADDOP(c, NO_LOCATION, POP_ITER); + } + else { + VISIT(c, expr, elt); + ADDOP_YIELD(c, elt_loc); + ADDOP(c, elt_loc, POP_TOP); + } break; case COMP_LISTCOMP: - VISIT(c, expr, elt); - ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); + if (elt->kind == Starred_kind) { + VISIT(c, expr, elt->v.Starred.value); + ADDOP_I(c, elt_loc, LIST_EXTEND, depth + 1); + } + else { + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, LIST_APPEND, depth + 1); + } break; case COMP_SETCOMP: - VISIT(c, expr, elt); - ADDOP_I(c, elt_loc, SET_ADD, depth + 1); + if (elt->kind == Starred_kind) { + VISIT(c, expr, elt->v.Starred.value); + ADDOP_I(c, elt_loc, SET_UPDATE, depth + 1); + } + else { + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, SET_ADD, depth + 1); + } break; case COMP_DICTCOMP: - /* With '{k: v}', k is evaluated before v, so we do - the same. */ - VISIT(c, expr, elt); - VISIT(c, expr, val); - elt_loc = LOCATION(elt->lineno, - val->end_lineno, - elt->col_offset, - val->end_col_offset); - ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); + if (val == NULL) { + /* unpacking (**) case */ + VISIT(c, expr, elt); + ADDOP_I(c, elt_loc, DICT_UPDATE, depth+1); + } + else { + /* With '{k: v}', k is evaluated before v, so we do + the same. */ + VISIT(c, expr, elt); + VISIT(c, expr, val); + elt_loc = LOCATION(elt->lineno, + val->end_lineno, + elt->col_offset, + val->end_col_offset); + ADDOP_I(c, elt_loc, MAP_ADD, depth + 1); + } break; default: return ERROR; From db61f622c6e3185fc499e69fc933f8cd42738fd3 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 1 Feb 2026 13:01:45 +0900 Subject: [PATCH 117/133] Fix unused variable 'COLORS' warning in optimizer.c (#144373) --- Python/optimizer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/optimizer.c b/Python/optimizer.c index b8208c7d888..2802ef17dbf 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -1993,6 +1993,8 @@ find_line_number(PyCodeObject *code, _PyExecutorObject *executor) #define BLACK "#000000" #define LOOP "#00c000" +#ifdef Py_STATS + static const char *COLORS[10] = { "9", "8", @@ -2005,8 +2007,6 @@ static const char *COLORS[10] = { "1", WHITE, }; - -#ifdef Py_STATS const char * get_background_color(_PyUOpInstruction const *inst, uint64_t max_hotness) { From b6256014be7ff8adf100c47c4be8bc002e0607d6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 31 Jan 2026 20:05:46 -0800 Subject: [PATCH 118/133] gh-144348: annotationlib: fix test that relies on set ordering (#144359) --- Lib/test/test_annotationlib.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index 6b75da32fa9..e89d6c0b161 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -121,8 +121,8 @@ def f( beta: +some, gamma: some < obj, delta: some | {obj: module}, - epsilon: some | {obj, module}, - zeta: some | [obj], + epsilon: some | {obj}, + zeta: some | [obj, module], eta: some | (), ): pass @@ -158,11 +158,11 @@ def f( epsilon_anno = anno["epsilon"] self.assertIsInstance(epsilon_anno, ForwardRef) - self.assertEqual(epsilon_anno, support.EqualToForwardRef("some | {obj, module}", owner=f)) + self.assertEqual(epsilon_anno, support.EqualToForwardRef("some | {obj}", owner=f)) zeta_anno = anno["zeta"] self.assertIsInstance(zeta_anno, ForwardRef) - self.assertEqual(zeta_anno, support.EqualToForwardRef("some | [obj]", owner=f)) + self.assertEqual(zeta_anno, support.EqualToForwardRef("some | [obj, module]", owner=f)) eta_anno = anno["eta"] self.assertIsInstance(eta_anno, ForwardRef) From 18347417b06d09fa7eeac68f88eb1e720e925c65 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 1 Feb 2026 15:25:59 +0200 Subject: [PATCH 119/133] gh-143904: Raise OverflowError instead of IndexError for too large offset in struct.pack_into() (GH-143905) --- Lib/test/test_struct.py | 4 +- ...-01-16-14-02-39.gh-issue-143904.rErHHA.rst | 2 + Modules/_struct.c | 21 ++++------ Modules/clinic/_struct.c.h | 40 ++++++++++++++----- 4 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-16-14-02-39.gh-issue-143904.rErHHA.rst diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 59133e24e64..bffbcb1a607 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -478,9 +478,9 @@ def _test_pack_into(self, pack_into): pack_into(writable_buf, None, test_string) with self.assertRaises(TypeError): pack_into(writable_buf, 0.0, test_string) - with self.assertRaises((IndexError, OverflowError)): + with self.assertRaises(OverflowError): pack_into(writable_buf, 2**1000, test_string) - with self.assertRaises((IndexError, OverflowError)): + with self.assertRaises(OverflowError): pack_into(writable_buf, -2**1000, test_string) def test_pack_into(self): diff --git a/Misc/NEWS.d/next/Library/2026-01-16-14-02-39.gh-issue-143904.rErHHA.rst b/Misc/NEWS.d/next/Library/2026-01-16-14-02-39.gh-issue-143904.rErHHA.rst new file mode 100644 index 00000000000..f856a4be9fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-16-14-02-39.gh-issue-143904.rErHHA.rst @@ -0,0 +1,2 @@ +:func:`struct.pack_into` now raises OverflowError instead of IndexError for +too large *offset* argument. diff --git a/Modules/_struct.c b/Modules/_struct.c index 74ae9e4c33d..7d2dfc591a2 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -2275,7 +2275,7 @@ Struct_pack_impl(PyStructObject *self, PyObject * const *values, Struct.pack_into buffer: Py_buffer(accept={rwbuffer}) - offset as offset_obj: object + offset: Py_ssize_t / *values: array @@ -2289,11 +2289,10 @@ help(struct) for more on format strings. static PyObject * Struct_pack_into_impl(PyStructObject *self, Py_buffer *buffer, - PyObject *offset_obj, PyObject * const *values, + Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length) -/*[clinic end generated code: output=b0c2ef496135dad3 input=d0de9b9f138c782d]*/ +/*[clinic end generated code: output=aa9d9a93f5f8f77b input=9d842a368ee14245]*/ { - Py_ssize_t offset; _structmodulestate *state = get_struct_state_structinst(self); ENSURE_STRUCT_IS_READY(self); @@ -2304,12 +2303,6 @@ Struct_pack_into_impl(PyStructObject *self, Py_buffer *buffer, return NULL; } - /* Extract the offset from the first argument */ - offset = PyNumber_AsSsize_t(offset_obj, PyExc_IndexError); - if (offset == -1 && PyErr_Occurred()) { - return NULL; - } - /* Support negative offsets. */ if (offset < 0) { /* Check that negative offset is low enough to fit data */ @@ -2546,7 +2539,7 @@ pack_into format as s_object: cache_struct buffer: Py_buffer(accept={rwbuffer}) - offset as offset_obj: object + offset: Py_ssize_t / *values: array @@ -2560,11 +2553,11 @@ strings. static PyObject * pack_into_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, - PyObject *offset_obj, PyObject * const *values, + Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length) -/*[clinic end generated code: output=148ef659a490eec3 input=3c5fe5bd3b6fd396]*/ +/*[clinic end generated code: output=e8bf7d422b2088ef input=086867c0f5d8a8e4]*/ { - return Struct_pack_into_impl(s_object, buffer, offset_obj, + return Struct_pack_into_impl(s_object, buffer, offset, values, values_length); } diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h index 11cd26174a3..9c9d29748fc 100644 --- a/Modules/clinic/_struct.c.h +++ b/Modules/clinic/_struct.c.h @@ -267,7 +267,7 @@ PyDoc_STRVAR(Struct_pack_into__doc__, static PyObject * Struct_pack_into_impl(PyStructObject *self, Py_buffer *buffer, - PyObject *offset_obj, PyObject * const *values, + Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length); static PyObject * @@ -275,7 +275,7 @@ Struct_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; Py_buffer buffer = {NULL, NULL}; - PyObject *offset_obj; + Py_ssize_t offset; PyObject * const *values; Py_ssize_t values_length; @@ -286,10 +286,21 @@ Struct_pack_into(PyObject *self, PyObject *const *args, Py_ssize_t nargs) _PyArg_BadArgument("pack_into", "argument 1", "read-write bytes-like object", args[0]); goto exit; } - offset_obj = args[1]; + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + offset = ival; + } values = args + 2; values_length = nargs - 2; - return_value = Struct_pack_into_impl((PyStructObject *)self, &buffer, offset_obj, values, values_length); + return_value = Struct_pack_into_impl((PyStructObject *)self, &buffer, offset, values, values_length); exit: /* Cleanup for buffer */ @@ -427,7 +438,7 @@ PyDoc_STRVAR(pack_into__doc__, static PyObject * pack_into_impl(PyObject *module, PyStructObject *s_object, Py_buffer *buffer, - PyObject *offset_obj, PyObject * const *values, + Py_ssize_t offset, PyObject * const *values, Py_ssize_t values_length); static PyObject * @@ -436,7 +447,7 @@ pack_into(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; PyStructObject *s_object = NULL; Py_buffer buffer = {NULL, NULL}; - PyObject *offset_obj; + Py_ssize_t offset; PyObject * const *values; Py_ssize_t values_length; @@ -450,10 +461,21 @@ pack_into(PyObject *module, PyObject *const *args, Py_ssize_t nargs) _PyArg_BadArgument("pack_into", "argument 2", "read-write bytes-like object", args[1]); goto exit; } - offset_obj = args[2]; + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + offset = ival; + } values = args + 3; values_length = nargs - 3; - return_value = pack_into_impl(module, s_object, &buffer, offset_obj, values, values_length); + return_value = pack_into_impl(module, s_object, &buffer, offset, values, values_length); exit: /* Cleanup for s_object */ @@ -642,4 +664,4 @@ exit: return return_value; } -/*[clinic end generated code: output=dc4f86c77ab3b1c9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=09ee4ac45b7e709b input=a9049054013a1b77]*/ From 3a0e1835563e6acfa3059a7d9777260cb2b6717d Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Sun, 1 Feb 2026 17:39:26 -0800 Subject: [PATCH 120/133] gh-144277: Fix usage of free-threaded terminology in the documentation (GH-144333) --- Doc/c-api/object.rst | 8 ++++---- Doc/c-api/refcounting.rst | 2 +- Doc/glossary.rst | 13 ++++++++++--- Doc/library/ctypes.rst | 2 +- Doc/library/io.rst | 2 +- Doc/library/site.rst | 2 +- Doc/using/configure.rst | 2 +- 7 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst index 127b50ac479..992a4383f97 100644 --- a/Doc/c-api/object.rst +++ b/Doc/c-api/object.rst @@ -711,10 +711,10 @@ Object Protocol :c:func:`PyUnstable_EnableTryIncRef` must have been called earlier on *obj* or this function may spuriously return ``0`` in the - :term:`free threading` build. + :term:`free-threaded build`. This function is logically equivalent to the following C code, except that - it behaves atomically in the :term:`free threading` build:: + it behaves atomically in the :term:`free-threaded build`:: if (Py_REFCNT(op) > 0) { Py_INCREF(op); @@ -791,10 +791,10 @@ Object Protocol On GIL-enabled builds, this function is equivalent to :c:expr:`Py_REFCNT(op) == 1`. - On a :term:`free threaded ` build, this checks if *op*'s + On a :term:`free-threaded build`, this checks if *op*'s :term:`reference count` is equal to one and additionally checks if *op* is only used by this thread. :c:expr:`Py_REFCNT(op) == 1` is **not** - thread-safe on free threaded builds; prefer this function. + thread-safe on free-threaded builds; prefer this function. The caller must hold an :term:`attached thread state`, despite the fact that this function doesn't call into the Python interpreter. This function diff --git a/Doc/c-api/refcounting.rst b/Doc/c-api/refcounting.rst index 57a0728d4e9..4d56a92bf2a 100644 --- a/Doc/c-api/refcounting.rst +++ b/Doc/c-api/refcounting.rst @@ -25,7 +25,7 @@ of Python objects. .. note:: - On :term:`free threaded ` builds of Python, returning 1 + On :term:`free-threaded builds ` of Python, returning 1 isn't sufficient to determine if it's safe to treat *o* as having no access by other threads. Use :c:func:`PyUnstable_Object_IsUniquelyReferenced` for that instead. diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 68035c2dfb5..7c41f5bc27b 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -160,9 +160,9 @@ Glossary On most builds of Python, having an attached thread state implies that the caller holds the :term:`GIL` for the current interpreter, so only one OS thread can have an attached thread state at a given moment. In - :term:`free-threaded ` builds of Python, threads can concurrently - hold an attached thread state, allowing for true parallelism of the bytecode - interpreter. + :term:`free-threaded builds ` of Python, threads can + concurrently hold an attached thread state, allowing for true parallelism of + the bytecode interpreter. attribute A value associated with an object which is usually referenced by name @@ -580,6 +580,13 @@ Glossary the :term:`global interpreter lock` which allows only one thread to execute Python bytecode at a time. See :pep:`703`. + free-threaded build + + A build of :term:`CPython` that supports :term:`free threading`, + configured using the :option:`--disable-gil` option before compilation. + + See :ref:`freethreading-python-howto`. + free variable Formally, as defined in the :ref:`language execution model `, a free variable is any variable used in a namespace which is not a local variable in that diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 6038af99009..d2f4da08327 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -896,7 +896,7 @@ invalid non-\ ``NULL`` pointers would crash Python):: Thread safety without the GIL ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -From Python 3.13 onward, the :term:`GIL` can be disabled on :term:`free threaded ` builds. +From Python 3.13 onward, the :term:`GIL` can be disabled on the :term:`free-threaded build`. In ctypes, reads and writes to a single object concurrently is safe, but not across multiple objects: .. code-block:: pycon diff --git a/Doc/library/io.rst b/Doc/library/io.rst index dfebccb5a9c..d1a9132db81 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -720,7 +720,7 @@ than raw I/O does. contains initial data. Methods may be used from multiple threads without external locking in - :term:`free threading` builds. + :term:`free-threaded builds `. :class:`BytesIO` provides or overrides these methods in addition to those from :class:`BufferedIOBase` and :class:`IOBase`: diff --git a/Doc/library/site.rst b/Doc/library/site.rst index d93e4dc7c75..ca2ac3b0098 100644 --- a/Doc/library/site.rst +++ b/Doc/library/site.rst @@ -34,7 +34,7 @@ For the head part, it uses ``sys.prefix`` and ``sys.exec_prefix``; empty heads are skipped. For the tail part, it uses the empty string and then :file:`lib/site-packages` (on Windows) or :file:`lib/python{X.Y[t]}/site-packages` (on Unix and macOS). (The -optional suffix "t" indicates the :term:`free threading` build, and is +optional suffix "t" indicates the :term:`free-threaded build`, and is appended if ``"t"`` is present in the :data:`sys.abiflags` constant.) For each of the distinct head-tail combinations, it sees if it refers to an existing diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index 26322045879..50812358a69 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -421,7 +421,7 @@ General Options :no-typesetting: Enables support for running Python without the :term:`global interpreter - lock` (GIL): free threading build. + lock` (GIL): :term:`free-threaded build`. Defines the ``Py_GIL_DISABLED`` macro and adds ``"t"`` to :data:`sys.abiflags`. From 40d07cad38bf3ce60f4ca03f1836e8650fe40df5 Mon Sep 17 00:00:00 2001 From: Ruiyang Ke Date: Mon, 2 Feb 2026 02:04:18 -0800 Subject: [PATCH 121/133] gh-144380: Fix incorrect type check in `buffered_iternext()` (#144381) --- .../Library/2026-02-01-15-25-00.gh-issue-144380.U7py_s.rst | 1 + Modules/_io/bufferedio.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-01-15-25-00.gh-issue-144380.U7py_s.rst diff --git a/Misc/NEWS.d/next/Library/2026-02-01-15-25-00.gh-issue-144380.U7py_s.rst b/Misc/NEWS.d/next/Library/2026-02-01-15-25-00.gh-issue-144380.U7py_s.rst new file mode 100644 index 00000000000..4b5b1b3776d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-01-15-25-00.gh-issue-144380.U7py_s.rst @@ -0,0 +1 @@ +Improve performance of :class:`io.BufferedReader` line iteration by ~49%. diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c index 6d779abd89c..0fdae7b2d21 100644 --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -1505,8 +1505,8 @@ buffered_iternext(PyObject *op) _PyIO_State *state = find_io_state_by_def(Py_TYPE(self)); tp = Py_TYPE(self); - if (Py_IS_TYPE(tp, state->PyBufferedReader_Type) || - Py_IS_TYPE(tp, state->PyBufferedRandom_Type)) + if (tp == state->PyBufferedReader_Type || + tp == state->PyBufferedRandom_Type) { /* Skip method call overhead for speed */ line = _buffered_readline(self, -1); From 092ef634f57909651c7699a3c750b16a1c0b63af Mon Sep 17 00:00:00 2001 From: Guilherme Leobas Date: Mon, 2 Feb 2026 07:30:17 -0300 Subject: [PATCH 122/133] docs: update dangling reference to `LOAD_METHOD` in dis.rst (#144358) --- Doc/library/dis.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 755d681b9df..1486eeb3053 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1642,7 +1642,7 @@ iterations of the loop. Pushes a ``NULL`` to the stack. Used in the call sequence to match the ``NULL`` pushed by - :opcode:`!LOAD_METHOD` for non-method calls. + :opcode:`LOAD_ATTR` for non-method calls. .. versionadded:: 3.11 From 15c9f2491d235ca1bebfbfbdefdd8d6ac3869298 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 2 Feb 2026 14:34:02 +0300 Subject: [PATCH 123/133] gh-115231: Fill __module__ for built-in staticmethods (#115232) Co-authored-by: Nikita Sobolev Co-authored-by: Victor Stinner --- Lib/test/test_funcattrs.py | 18 ++++++++++++++++++ ...4-02-10-05-42-26.gh-issue-115231.6T7dzi.rst | 2 ++ Objects/typeobject.c | 10 +++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-02-10-05-42-26.gh-issue-115231.6T7dzi.rst diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 375f456dfde..fe14e7cb342 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -459,6 +459,24 @@ class BuiltinFunctionPropertiesTest(unittest.TestCase): # XXX Not sure where this should really go since I can't find a # test module specifically for builtin_function_or_method. + def test_builtin__module__(self): + import math + + # builtin function: + self.assertEqual(len.__module__, 'builtins') + self.assertEqual(math.sin.__module__, 'math') + + # instance method: + self.assertRaises(AttributeError, getattr, int.to_bytes, '__module__') + self.assertEqual(int.to_bytes.__objclass__.__module__, 'builtins') + + # builtin classmethod: + self.assertEqual(int.from_bytes.__module__, None) + self.assertEqual(int.from_bytes.__self__.__module__, 'builtins') + + # builtin staticmethod: + self.assertEqual(bytes.maketrans.__module__, 'builtins') + def test_builtin__qualname__(self): import time diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-02-10-05-42-26.gh-issue-115231.6T7dzi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-02-10-05-42-26.gh-issue-115231.6T7dzi.rst new file mode 100644 index 00000000000..0e41bc963be --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-02-10-05-42-26.gh-issue-115231.6T7dzi.rst @@ -0,0 +1,2 @@ +Setup ``__module__`` attribute for built-in static methods. Patch by Sergey +B Kirpichev. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 54263fd603e..2905b9ba562 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8361,7 +8361,15 @@ type_add_method(PyTypeObject *type, PyMethodDef *meth) descr = PyDescr_NewClassMethod(type, meth); } else if (meth->ml_flags & METH_STATIC) { - PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, NULL); + PyObject *mod = type_module(type); + if (mod == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return -1; + } + PyErr_Clear(); + } + PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, mod); + Py_XDECREF(mod); if (cfunc == NULL) { return -1; } From c3b61ef73da376620ca89b2db12e98bff1746d61 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 2 Feb 2026 13:38:32 +0200 Subject: [PATCH 124/133] gh-144001: Simplify Base64 decoding with altchars and ignorechars specified (GH-144324) Treat "+" and "/" like other characters not in the alternative Base64 alphabet when both altchars and ignorechars are specified. E.g. discard them if they are not in altchars but are in ignorechars, and set error if they are not in altchars and not in ignorechars. Only emit warnings if ignorechars is not specified. --- Doc/library/base64.rst | 10 +++++----- Lib/base64.py | 42 +++++++++++++++-------------------------- Lib/test/test_base64.py | 39 ++++++++++++++++++++------------------ 3 files changed, 41 insertions(+), 50 deletions(-) diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst index 65b8aeaef8e..478686bc300 100644 --- a/Doc/library/base64.rst +++ b/Doc/library/base64.rst @@ -91,7 +91,8 @@ POST request. ``False`` otherwise. If *validate* is false, characters that are neither - in the normal base-64 alphabet nor the alternative alphabet are + in the normal base-64 alphabet nor (if *ignorechars* is not specified) + the alternative alphabet are discarded prior to the padding check, but the ``+`` and ``/`` characters keep their meaning if they are not in *altchars* (they will be discarded in future Python versions). @@ -101,15 +102,14 @@ POST request. For more information about the strict base64 check, see :func:`binascii.a2b_base64` + .. versionchanged:: next + Added the *ignorechars* parameter. + .. deprecated:: next Accepting the ``+`` and ``/`` characters with an alternative alphabet is now deprecated. - .. versionchanged:: next - Added the *ignorechars* parameter. - - .. function:: standard_b64encode(s) Encode :term:`bytes-like object` *s* using the standard Base64 alphabet diff --git a/Lib/base64.py b/Lib/base64.py index 6e9d24f0649..7cb22e3efc1 100644 --- a/Lib/base64.py +++ b/Lib/base64.py @@ -89,49 +89,37 @@ def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPE s = _bytes_from_decode_data(s) if validate is _NOT_SPECIFIED: validate = ignorechars is not _NOT_SPECIFIED - if ignorechars is _NOT_SPECIFIED: - ignorechars = b'' badchar = None - badchar_strict = False if altchars is not None: altchars = _bytes_from_decode_data(altchars) if len(altchars) != 2: raise ValueError(f'invalid altchars: {altchars!r}') - for b in b'+/': - if b not in altchars and b in s: - if badchar is None: - badchar = b - if not validate: - break - if not isinstance(ignorechars, (bytes, bytearray)): - ignorechars = memoryview(ignorechars).cast('B') - if b not in ignorechars: - badchar_strict = True + if ignorechars is _NOT_SPECIFIED: + for b in b'+/': + if b not in altchars and b in s: badchar = b break - s = s.translate(bytes.maketrans(altchars, b'+/')) + s = s.translate(bytes.maketrans(altchars, b'+/')) + else: + trans = bytes.maketrans(b'+/' + altchars, altchars + b'+/') + s = s.translate(trans) + ignorechars = ignorechars.translate(trans) + if ignorechars is _NOT_SPECIFIED: + ignorechars = b'' result = binascii.a2b_base64(s, strict_mode=validate, ignorechars=ignorechars) if badchar is not None: import warnings - if badchar_strict: + if validate: warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' f'with altchars={altchars!r} and validate=True ' f'will be an error in future Python versions', DeprecationWarning, stacklevel=2) else: - ignorechars = bytes(ignorechars) - if ignorechars: - warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' - f'with altchars={altchars!r} ' - f'and ignorechars={ignorechars!r} ' - f'will be discarded in future Python versions', - FutureWarning, stacklevel=2) - else: - warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' - f'with altchars={altchars!r} and validate=False ' - f'will be discarded in future Python versions', - FutureWarning, stacklevel=2) + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=False ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) return result diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py index 5f7a41f5334..0f947409f06 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py @@ -291,6 +291,7 @@ def test_b64decode_altchars(self): eq(base64.b64decode(data_str, altchars=altchars), res) eq(base64.b64decode(data, altchars=altchars_str), res) eq(base64.b64decode(data_str, altchars=altchars_str), res) + eq(base64.b64decode(data, altchars=altchars, ignorechars=b'\n'), res) self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+') self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-') @@ -370,26 +371,28 @@ def test_b64decode_invalid_chars(self): self.assertEqual(r, b'\xff\xff\xff') self.assertEqual(str(cm.warning), error % ('/', "altchars=b'-_' and validate=True")) - with self.assertWarns(FutureWarning) as cm: - r = base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'+') - self.assertEqual(r, b'\xfb\xef\xbe') - self.assertEqual(str(cm.warning), - discarded % ('+', "altchars=b'-_' and ignorechars=b'+'")) - with self.assertWarns(FutureWarning) as cm: - r = base64.b64decode(b'////', altchars=b'-_', ignorechars=b'/') - self.assertEqual(r, b'\xff\xff\xff') - self.assertEqual(str(cm.warning), - discarded % ('/', "altchars=b'-_' and ignorechars=b'/'")) - with self.assertWarns(DeprecationWarning) as cm: - r = base64.b64decode(b'++++////', altchars=b'-_', ignorechars=b'+') + r = base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'+') + self.assertEqual(r, b'') + r = base64.b64decode(b'////', altchars=b'-_', ignorechars=b'/') + self.assertEqual(r, b'') + r = base64.b64decode(b'++++////', altchars=b'-_', validate=False, ignorechars=b'') + self.assertEqual(r, b'') + with self.assertRaisesRegex(binascii.Error, 'Only base64 data is allowed'): + base64.b64decode(b'////', altchars=b'-_', ignorechars=b'') + with self.assertRaisesRegex(binascii.Error, 'Only base64 data is allowed'): + base64.b64decode(b'++++', altchars=b'-_', ignorechars=b'') + r = base64.b64decode(b'++++YWJj----____', altchars=b'-_', ignorechars=b'+') + self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff') + r = base64.b64decode(b'////YWJj----____', altchars=b'-_', ignorechars=b'/') + self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff') + r = base64.b64decode(b'++++,,,,', altchars=b'+,', ignorechars=b'+') self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff') - self.assertEqual(str(cm.warning), - error % ('/', "altchars=b'-_' and validate=True")) - with self.assertWarns(DeprecationWarning) as cm: - r = base64.b64decode(b'++++////', altchars=b'-_', ignorechars=b'/') + r = base64.b64decode(b'////YWJj++++,,,,', altchars=b'+,', ignorechars=b'/') + self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff') + r = base64.b64decode(b'----////', altchars=b'-/', ignorechars=b'/') self.assertEqual(r, b'\xfb\xef\xbe\xff\xff\xff') - self.assertEqual(str(cm.warning), - error % ('+', "altchars=b'-_' and validate=True")) + r = base64.b64decode(b'++++YWJj----////', altchars=b'-/', ignorechars=b'+') + self.assertEqual(r, b'abc\xfb\xef\xbe\xff\xff\xff') with self.assertWarns(FutureWarning) as cm: self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe') From ebbb2ca81f8a33d8b9a5d94f1c4f99a32ee0f427 Mon Sep 17 00:00:00 2001 From: Hai Zhu Date: Mon, 2 Feb 2026 22:09:54 +0800 Subject: [PATCH 125/133] gh-144145: Revert PR#144122 for performance and potential bugs. (GH-144391) Revert "gh-144145: Track nullness of properties in the Tier 2 JIT optimizer (GH-144122)" This reverts commit 1dc12b2883c89045469f3c401157d4df13f535f0. --- Include/internal/pycore_optimizer.h | 8 - Include/internal/pycore_optimizer_types.h | 36 - Include/internal/pycore_uop_ids.h | 1788 ++++++++--------- Include/internal/pycore_uop_metadata.h | 42 - ...-01-30-09-47-29.gh-issue-144145.mxJyUj.rst | 1 - Python/bytecodes.c | 31 - Python/executor_cases.c.h | 292 --- Python/optimizer_analysis.c | 12 +- Python/optimizer_bytecodes.c | 31 +- Python/optimizer_cases.c.h | 50 +- Python/optimizer_symbols.c | 200 +- 11 files changed, 902 insertions(+), 1589 deletions(-) delete mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 89e08e86ed6..2ee518fb82f 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -37,15 +37,10 @@ typedef struct _JitOptContext { // Arena for the symbolic types. ty_arena t_arena; - // Arena for the descriptor mappings. - descr_arena d_arena; - JitOptRef *n_consumed; JitOptRef *limit; JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE]; _PyJitUopBuffer out_buffer; - // Index of the last escaped uop in out_buffer. - int last_escape_index; } JitOptContext; @@ -300,9 +295,6 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value, extern bool _Py_uop_sym_is_compact_int(JitOptRef sym); extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx); extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym); -extern JitOptRef _Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version); -extern JitOptRef _Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index); -extern JitOptRef _Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value); extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind); extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true); diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index 1996ce10735..b4b93e83538 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -16,10 +16,6 @@ extern "C" { #define TY_ARENA_SIZE (UOP_MAX_TRACE_LENGTH * 5) -// Maximum descriptor mappings per object tracked symbolically -#define MAX_SYMBOLIC_DESCR_SIZE 16 -#define DESCR_ARENA_SIZE (MAX_SYMBOLIC_DESCR_SIZE * 100) - // Need extras for root frame and for overflow frame (see TRACE_STACK_PUSH()) #define MAX_ABSTRACT_FRAME_DEPTH (16) @@ -45,7 +41,6 @@ typedef enum _JitSymType { JIT_SYM_TRUTHINESS_TAG = 9, JIT_SYM_COMPACT_INT = 10, JIT_SYM_PREDICATE_TAG = 11, - JIT_SYM_DESCR_TAG = 12, } JitSymType; typedef struct _jit_opt_known_class { @@ -96,31 +91,6 @@ typedef struct { uint8_t tag; } JitOptCompactInt; -/* -Mapping from slot index or attribute offset to its symbolic value. -SAFETY: -This structure is used for both STORE_ATTR_SLOT and STORE_ATTR_INSTANCE_VALUE. -These two never appear on the same object type because: -__slots__ classes don't have Py_TPFLAGS_INLINE_VALUES -Therefore, there is no index collision between slot offsets and inline value offsets. -Note: -STORE_ATTR_WITH_HINT is NOT currently tracked. -If we want to track it in the future, we need to be careful about -potential index collisions with STORE_ATTR_INSTANCE_VALUE. -*/ -typedef struct { - uint16_t slot_index; - uint16_t symbol; -} JitOptDescrMapping; - -typedef struct _jit_opt_descr { - uint8_t tag; - uint8_t num_descrs; - uint16_t last_modified_index; // Index in out_buffer when this object was last modified - uint32_t type_version; - JitOptDescrMapping *descrs; -} JitOptDescrObject; - typedef union _jit_opt_symbol { uint8_t tag; JitOptKnownClass cls; @@ -129,7 +99,6 @@ typedef union _jit_opt_symbol { JitOptTuple tuple; JitOptTruthiness truthiness; JitOptCompactInt compact; - JitOptDescrObject descr; JitOptPredicate predicate; } JitOptSymbol; @@ -159,11 +128,6 @@ typedef struct ty_arena { JitOptSymbol arena[TY_ARENA_SIZE]; } ty_arena; -typedef struct descr_arena { - int descr_curr_number; - int descr_max_number; - JitOptDescrMapping arena[DESCR_ARENA_SIZE]; -} descr_arena; #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index a1abe168605..8712d1afc75 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -340,915 +340,905 @@ extern "C" { #define _START_EXECUTOR 548 #define _STORE_ATTR 549 #define _STORE_ATTR_INSTANCE_VALUE 550 -#define _STORE_ATTR_INSTANCE_VALUE_NULL 551 -#define _STORE_ATTR_SLOT 552 -#define _STORE_ATTR_SLOT_NULL 553 -#define _STORE_ATTR_WITH_HINT 554 +#define _STORE_ATTR_SLOT 551 +#define _STORE_ATTR_WITH_HINT 552 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 555 -#define _STORE_SUBSCR 556 -#define _STORE_SUBSCR_DICT 557 -#define _STORE_SUBSCR_LIST_INT 558 -#define _SWAP 559 -#define _SWAP_2 560 -#define _SWAP_3 561 -#define _SWAP_FAST 562 -#define _SWAP_FAST_0 563 -#define _SWAP_FAST_1 564 -#define _SWAP_FAST_2 565 -#define _SWAP_FAST_3 566 -#define _SWAP_FAST_4 567 -#define _SWAP_FAST_5 568 -#define _SWAP_FAST_6 569 -#define _SWAP_FAST_7 570 -#define _TIER2_RESUME_CHECK 571 -#define _TO_BOOL 572 +#define _STORE_SLICE 553 +#define _STORE_SUBSCR 554 +#define _STORE_SUBSCR_DICT 555 +#define _STORE_SUBSCR_LIST_INT 556 +#define _SWAP 557 +#define _SWAP_2 558 +#define _SWAP_3 559 +#define _SWAP_FAST 560 +#define _SWAP_FAST_0 561 +#define _SWAP_FAST_1 562 +#define _SWAP_FAST_2 563 +#define _SWAP_FAST_3 564 +#define _SWAP_FAST_4 565 +#define _SWAP_FAST_5 566 +#define _SWAP_FAST_6 567 +#define _SWAP_FAST_7 568 +#define _TIER2_RESUME_CHECK 569 +#define _TO_BOOL 570 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 573 -#define _TO_BOOL_LIST 574 +#define _TO_BOOL_INT 571 +#define _TO_BOOL_LIST 572 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 575 +#define _TO_BOOL_STR 573 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 576 -#define _UNARY_NEGATIVE 577 +#define _UNARY_INVERT 574 +#define _UNARY_NEGATIVE 575 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 578 -#define _UNPACK_SEQUENCE_LIST 579 -#define _UNPACK_SEQUENCE_TUPLE 580 -#define _UNPACK_SEQUENCE_TWO_TUPLE 581 +#define _UNPACK_SEQUENCE 576 +#define _UNPACK_SEQUENCE_LIST 577 +#define _UNPACK_SEQUENCE_TUPLE 578 +#define _UNPACK_SEQUENCE_TWO_TUPLE 579 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 581 -#define _BINARY_OP_r23 582 -#define _BINARY_OP_ADD_FLOAT_r03 583 -#define _BINARY_OP_ADD_FLOAT_r13 584 -#define _BINARY_OP_ADD_FLOAT_r23 585 -#define _BINARY_OP_ADD_INT_r03 586 -#define _BINARY_OP_ADD_INT_r13 587 -#define _BINARY_OP_ADD_INT_r23 588 -#define _BINARY_OP_ADD_UNICODE_r03 589 -#define _BINARY_OP_ADD_UNICODE_r13 590 -#define _BINARY_OP_ADD_UNICODE_r23 591 -#define _BINARY_OP_EXTEND_r23 592 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 593 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 594 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 595 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 596 -#define _BINARY_OP_MULTIPLY_INT_r03 597 -#define _BINARY_OP_MULTIPLY_INT_r13 598 -#define _BINARY_OP_MULTIPLY_INT_r23 599 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 600 -#define _BINARY_OP_SUBSCR_DICT_r23 601 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 602 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 603 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 604 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 605 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 606 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 607 -#define _BINARY_OP_SUBSCR_STR_INT_r23 608 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 609 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 610 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 611 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 612 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 613 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 614 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 615 -#define _BINARY_OP_SUBTRACT_INT_r03 616 -#define _BINARY_OP_SUBTRACT_INT_r13 617 -#define _BINARY_OP_SUBTRACT_INT_r23 618 -#define _BINARY_SLICE_r31 619 -#define _BUILD_INTERPOLATION_r01 620 -#define _BUILD_LIST_r01 621 -#define _BUILD_MAP_r01 622 -#define _BUILD_SET_r01 623 -#define _BUILD_SLICE_r01 624 -#define _BUILD_STRING_r01 625 -#define _BUILD_TEMPLATE_r21 626 -#define _BUILD_TUPLE_r01 627 -#define _CALL_BUILTIN_CLASS_r01 628 -#define _CALL_BUILTIN_FAST_r01 629 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 630 -#define _CALL_BUILTIN_O_r03 631 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 632 -#define _CALL_INTRINSIC_1_r11 633 -#define _CALL_INTRINSIC_2_r21 634 -#define _CALL_ISINSTANCE_r31 635 -#define _CALL_KW_NON_PY_r11 636 -#define _CALL_LEN_r33 637 -#define _CALL_LIST_APPEND_r03 638 -#define _CALL_LIST_APPEND_r13 639 -#define _CALL_LIST_APPEND_r23 640 -#define _CALL_LIST_APPEND_r33 641 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 642 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 643 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 644 -#define _CALL_METHOD_DESCRIPTOR_O_r03 645 -#define _CALL_NON_PY_GENERAL_r01 646 -#define _CALL_STR_1_r32 647 -#define _CALL_TUPLE_1_r32 648 -#define _CALL_TYPE_1_r02 649 -#define _CALL_TYPE_1_r12 650 -#define _CALL_TYPE_1_r22 651 -#define _CALL_TYPE_1_r32 652 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 653 -#define _CHECK_ATTR_CLASS_r01 654 -#define _CHECK_ATTR_CLASS_r11 655 -#define _CHECK_ATTR_CLASS_r22 656 -#define _CHECK_ATTR_CLASS_r33 657 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 658 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 659 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 660 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 661 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 662 -#define _CHECK_EG_MATCH_r22 663 -#define _CHECK_EXC_MATCH_r22 664 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 665 -#define _CHECK_FUNCTION_VERSION_r00 666 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 667 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 668 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 669 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 670 -#define _CHECK_FUNCTION_VERSION_KW_r11 671 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 672 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 673 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 674 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 675 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 676 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 677 -#define _CHECK_IS_PY_CALLABLE_EX_r03 678 -#define _CHECK_IS_PY_CALLABLE_EX_r13 679 -#define _CHECK_IS_PY_CALLABLE_EX_r23 680 -#define _CHECK_IS_PY_CALLABLE_EX_r33 681 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 682 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 683 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 684 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 685 -#define _CHECK_METHOD_VERSION_r00 686 -#define _CHECK_METHOD_VERSION_KW_r11 687 -#define _CHECK_PEP_523_r00 688 -#define _CHECK_PEP_523_r11 689 -#define _CHECK_PEP_523_r22 690 -#define _CHECK_PEP_523_r33 691 -#define _CHECK_PERIODIC_r00 692 -#define _CHECK_PERIODIC_AT_END_r00 693 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 694 -#define _CHECK_RECURSION_REMAINING_r00 695 -#define _CHECK_RECURSION_REMAINING_r11 696 -#define _CHECK_RECURSION_REMAINING_r22 697 -#define _CHECK_RECURSION_REMAINING_r33 698 -#define _CHECK_STACK_SPACE_r00 699 -#define _CHECK_STACK_SPACE_OPERAND_r00 700 -#define _CHECK_STACK_SPACE_OPERAND_r11 701 -#define _CHECK_STACK_SPACE_OPERAND_r22 702 -#define _CHECK_STACK_SPACE_OPERAND_r33 703 -#define _CHECK_VALIDITY_r00 704 -#define _CHECK_VALIDITY_r11 705 -#define _CHECK_VALIDITY_r22 706 -#define _CHECK_VALIDITY_r33 707 -#define _COLD_DYNAMIC_EXIT_r00 708 -#define _COLD_EXIT_r00 709 -#define _COMPARE_OP_r21 710 -#define _COMPARE_OP_FLOAT_r03 711 -#define _COMPARE_OP_FLOAT_r13 712 -#define _COMPARE_OP_FLOAT_r23 713 -#define _COMPARE_OP_INT_r23 714 -#define _COMPARE_OP_STR_r23 715 -#define _CONTAINS_OP_r23 716 -#define _CONTAINS_OP_DICT_r23 717 -#define _CONTAINS_OP_SET_r23 718 -#define _CONVERT_VALUE_r11 719 -#define _COPY_r01 720 -#define _COPY_1_r02 721 -#define _COPY_1_r12 722 -#define _COPY_1_r23 723 -#define _COPY_2_r03 724 -#define _COPY_2_r13 725 -#define _COPY_2_r23 726 -#define _COPY_3_r03 727 -#define _COPY_3_r13 728 -#define _COPY_3_r23 729 -#define _COPY_3_r33 730 -#define _COPY_FREE_VARS_r00 731 -#define _COPY_FREE_VARS_r11 732 -#define _COPY_FREE_VARS_r22 733 -#define _COPY_FREE_VARS_r33 734 -#define _CREATE_INIT_FRAME_r01 735 -#define _DELETE_ATTR_r10 736 -#define _DELETE_DEREF_r00 737 -#define _DELETE_FAST_r00 738 -#define _DELETE_GLOBAL_r00 739 -#define _DELETE_NAME_r00 740 -#define _DELETE_SUBSCR_r20 741 -#define _DEOPT_r00 742 -#define _DEOPT_r10 743 -#define _DEOPT_r20 744 -#define _DEOPT_r30 745 -#define _DICT_MERGE_r10 746 -#define _DICT_UPDATE_r10 747 -#define _DO_CALL_r01 748 -#define _DO_CALL_FUNCTION_EX_r31 749 -#define _DO_CALL_KW_r11 750 -#define _DYNAMIC_EXIT_r00 751 -#define _DYNAMIC_EXIT_r10 752 -#define _DYNAMIC_EXIT_r20 753 -#define _DYNAMIC_EXIT_r30 754 -#define _END_FOR_r10 755 -#define _END_SEND_r21 756 -#define _ERROR_POP_N_r00 757 -#define _EXIT_INIT_CHECK_r10 758 -#define _EXIT_TRACE_r00 759 -#define _EXIT_TRACE_r10 760 -#define _EXIT_TRACE_r20 761 -#define _EXIT_TRACE_r30 762 -#define _EXPAND_METHOD_r00 763 -#define _EXPAND_METHOD_KW_r11 764 -#define _FATAL_ERROR_r00 765 -#define _FATAL_ERROR_r11 766 -#define _FATAL_ERROR_r22 767 -#define _FATAL_ERROR_r33 768 -#define _FORMAT_SIMPLE_r11 769 -#define _FORMAT_WITH_SPEC_r21 770 -#define _FOR_ITER_r23 771 -#define _FOR_ITER_GEN_FRAME_r03 772 -#define _FOR_ITER_GEN_FRAME_r13 773 -#define _FOR_ITER_GEN_FRAME_r23 774 -#define _FOR_ITER_TIER_TWO_r23 775 -#define _GET_AITER_r11 776 -#define _GET_ANEXT_r12 777 -#define _GET_AWAITABLE_r11 778 -#define _GET_ITER_r12 779 -#define _GET_LEN_r12 780 -#define _GET_YIELD_FROM_ITER_r11 781 -#define _GUARD_BINARY_OP_EXTEND_r22 782 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 783 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 784 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 785 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 786 -#define _GUARD_BIT_IS_SET_POP_r00 787 -#define _GUARD_BIT_IS_SET_POP_r10 788 -#define _GUARD_BIT_IS_SET_POP_r21 789 -#define _GUARD_BIT_IS_SET_POP_r32 790 -#define _GUARD_BIT_IS_SET_POP_4_r00 791 -#define _GUARD_BIT_IS_SET_POP_4_r10 792 -#define _GUARD_BIT_IS_SET_POP_4_r21 793 -#define _GUARD_BIT_IS_SET_POP_4_r32 794 -#define _GUARD_BIT_IS_SET_POP_5_r00 795 -#define _GUARD_BIT_IS_SET_POP_5_r10 796 -#define _GUARD_BIT_IS_SET_POP_5_r21 797 -#define _GUARD_BIT_IS_SET_POP_5_r32 798 -#define _GUARD_BIT_IS_SET_POP_6_r00 799 -#define _GUARD_BIT_IS_SET_POP_6_r10 800 -#define _GUARD_BIT_IS_SET_POP_6_r21 801 -#define _GUARD_BIT_IS_SET_POP_6_r32 802 -#define _GUARD_BIT_IS_SET_POP_7_r00 803 -#define _GUARD_BIT_IS_SET_POP_7_r10 804 -#define _GUARD_BIT_IS_SET_POP_7_r21 805 -#define _GUARD_BIT_IS_SET_POP_7_r32 806 -#define _GUARD_BIT_IS_UNSET_POP_r00 807 -#define _GUARD_BIT_IS_UNSET_POP_r10 808 -#define _GUARD_BIT_IS_UNSET_POP_r21 809 -#define _GUARD_BIT_IS_UNSET_POP_r32 810 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 811 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 812 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 813 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 814 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 815 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 816 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 817 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 818 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 819 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 820 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 821 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 822 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 823 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 824 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 825 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 826 -#define _GUARD_CALLABLE_ISINSTANCE_r03 827 -#define _GUARD_CALLABLE_ISINSTANCE_r13 828 -#define _GUARD_CALLABLE_ISINSTANCE_r23 829 -#define _GUARD_CALLABLE_ISINSTANCE_r33 830 -#define _GUARD_CALLABLE_LEN_r03 831 -#define _GUARD_CALLABLE_LEN_r13 832 -#define _GUARD_CALLABLE_LEN_r23 833 -#define _GUARD_CALLABLE_LEN_r33 834 -#define _GUARD_CALLABLE_LIST_APPEND_r03 835 -#define _GUARD_CALLABLE_LIST_APPEND_r13 836 -#define _GUARD_CALLABLE_LIST_APPEND_r23 837 -#define _GUARD_CALLABLE_LIST_APPEND_r33 838 -#define _GUARD_CALLABLE_STR_1_r03 839 -#define _GUARD_CALLABLE_STR_1_r13 840 -#define _GUARD_CALLABLE_STR_1_r23 841 -#define _GUARD_CALLABLE_STR_1_r33 842 -#define _GUARD_CALLABLE_TUPLE_1_r03 843 -#define _GUARD_CALLABLE_TUPLE_1_r13 844 -#define _GUARD_CALLABLE_TUPLE_1_r23 845 -#define _GUARD_CALLABLE_TUPLE_1_r33 846 -#define _GUARD_CALLABLE_TYPE_1_r03 847 -#define _GUARD_CALLABLE_TYPE_1_r13 848 -#define _GUARD_CALLABLE_TYPE_1_r23 849 -#define _GUARD_CALLABLE_TYPE_1_r33 850 -#define _GUARD_DORV_NO_DICT_r01 851 -#define _GUARD_DORV_NO_DICT_r11 852 -#define _GUARD_DORV_NO_DICT_r22 853 -#define _GUARD_DORV_NO_DICT_r33 854 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 855 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 856 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 857 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 858 -#define _GUARD_GLOBALS_VERSION_r00 859 -#define _GUARD_GLOBALS_VERSION_r11 860 -#define _GUARD_GLOBALS_VERSION_r22 861 -#define _GUARD_GLOBALS_VERSION_r33 862 -#define _GUARD_IP_RETURN_GENERATOR_r00 863 -#define _GUARD_IP_RETURN_GENERATOR_r11 864 -#define _GUARD_IP_RETURN_GENERATOR_r22 865 -#define _GUARD_IP_RETURN_GENERATOR_r33 866 -#define _GUARD_IP_RETURN_VALUE_r00 867 -#define _GUARD_IP_RETURN_VALUE_r11 868 -#define _GUARD_IP_RETURN_VALUE_r22 869 -#define _GUARD_IP_RETURN_VALUE_r33 870 -#define _GUARD_IP_YIELD_VALUE_r00 871 -#define _GUARD_IP_YIELD_VALUE_r11 872 -#define _GUARD_IP_YIELD_VALUE_r22 873 -#define _GUARD_IP_YIELD_VALUE_r33 874 -#define _GUARD_IP__PUSH_FRAME_r00 875 -#define _GUARD_IP__PUSH_FRAME_r11 876 -#define _GUARD_IP__PUSH_FRAME_r22 877 -#define _GUARD_IP__PUSH_FRAME_r33 878 -#define _GUARD_IS_FALSE_POP_r00 879 -#define _GUARD_IS_FALSE_POP_r10 880 -#define _GUARD_IS_FALSE_POP_r21 881 -#define _GUARD_IS_FALSE_POP_r32 882 -#define _GUARD_IS_NONE_POP_r00 883 -#define _GUARD_IS_NONE_POP_r10 884 -#define _GUARD_IS_NONE_POP_r21 885 -#define _GUARD_IS_NONE_POP_r32 886 -#define _GUARD_IS_NOT_NONE_POP_r10 887 -#define _GUARD_IS_TRUE_POP_r00 888 -#define _GUARD_IS_TRUE_POP_r10 889 -#define _GUARD_IS_TRUE_POP_r21 890 -#define _GUARD_IS_TRUE_POP_r32 891 -#define _GUARD_KEYS_VERSION_r01 892 -#define _GUARD_KEYS_VERSION_r11 893 -#define _GUARD_KEYS_VERSION_r22 894 -#define _GUARD_KEYS_VERSION_r33 895 -#define _GUARD_NOS_COMPACT_ASCII_r02 896 -#define _GUARD_NOS_COMPACT_ASCII_r12 897 -#define _GUARD_NOS_COMPACT_ASCII_r22 898 -#define _GUARD_NOS_COMPACT_ASCII_r33 899 -#define _GUARD_NOS_DICT_r02 900 -#define _GUARD_NOS_DICT_r12 901 -#define _GUARD_NOS_DICT_r22 902 -#define _GUARD_NOS_DICT_r33 903 -#define _GUARD_NOS_FLOAT_r02 904 -#define _GUARD_NOS_FLOAT_r12 905 -#define _GUARD_NOS_FLOAT_r22 906 -#define _GUARD_NOS_FLOAT_r33 907 -#define _GUARD_NOS_INT_r02 908 -#define _GUARD_NOS_INT_r12 909 -#define _GUARD_NOS_INT_r22 910 -#define _GUARD_NOS_INT_r33 911 -#define _GUARD_NOS_LIST_r02 912 -#define _GUARD_NOS_LIST_r12 913 -#define _GUARD_NOS_LIST_r22 914 -#define _GUARD_NOS_LIST_r33 915 -#define _GUARD_NOS_NOT_NULL_r02 916 -#define _GUARD_NOS_NOT_NULL_r12 917 -#define _GUARD_NOS_NOT_NULL_r22 918 -#define _GUARD_NOS_NOT_NULL_r33 919 -#define _GUARD_NOS_NULL_r02 920 -#define _GUARD_NOS_NULL_r12 921 -#define _GUARD_NOS_NULL_r22 922 -#define _GUARD_NOS_NULL_r33 923 -#define _GUARD_NOS_OVERFLOWED_r02 924 -#define _GUARD_NOS_OVERFLOWED_r12 925 -#define _GUARD_NOS_OVERFLOWED_r22 926 -#define _GUARD_NOS_OVERFLOWED_r33 927 -#define _GUARD_NOS_TUPLE_r02 928 -#define _GUARD_NOS_TUPLE_r12 929 -#define _GUARD_NOS_TUPLE_r22 930 -#define _GUARD_NOS_TUPLE_r33 931 -#define _GUARD_NOS_UNICODE_r02 932 -#define _GUARD_NOS_UNICODE_r12 933 -#define _GUARD_NOS_UNICODE_r22 934 -#define _GUARD_NOS_UNICODE_r33 935 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 936 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 937 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 938 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 939 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 940 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 941 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 942 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 943 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 944 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 945 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 946 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 947 -#define _GUARD_THIRD_NULL_r03 948 -#define _GUARD_THIRD_NULL_r13 949 -#define _GUARD_THIRD_NULL_r23 950 -#define _GUARD_THIRD_NULL_r33 951 -#define _GUARD_TOS_ANY_SET_r01 952 -#define _GUARD_TOS_ANY_SET_r11 953 -#define _GUARD_TOS_ANY_SET_r22 954 -#define _GUARD_TOS_ANY_SET_r33 955 -#define _GUARD_TOS_DICT_r01 956 -#define _GUARD_TOS_DICT_r11 957 -#define _GUARD_TOS_DICT_r22 958 -#define _GUARD_TOS_DICT_r33 959 -#define _GUARD_TOS_FLOAT_r01 960 -#define _GUARD_TOS_FLOAT_r11 961 -#define _GUARD_TOS_FLOAT_r22 962 -#define _GUARD_TOS_FLOAT_r33 963 -#define _GUARD_TOS_INT_r01 964 -#define _GUARD_TOS_INT_r11 965 -#define _GUARD_TOS_INT_r22 966 -#define _GUARD_TOS_INT_r33 967 -#define _GUARD_TOS_LIST_r01 968 -#define _GUARD_TOS_LIST_r11 969 -#define _GUARD_TOS_LIST_r22 970 -#define _GUARD_TOS_LIST_r33 971 -#define _GUARD_TOS_OVERFLOWED_r01 972 -#define _GUARD_TOS_OVERFLOWED_r11 973 -#define _GUARD_TOS_OVERFLOWED_r22 974 -#define _GUARD_TOS_OVERFLOWED_r33 975 -#define _GUARD_TOS_SLICE_r01 976 -#define _GUARD_TOS_SLICE_r11 977 -#define _GUARD_TOS_SLICE_r22 978 -#define _GUARD_TOS_SLICE_r33 979 -#define _GUARD_TOS_TUPLE_r01 980 -#define _GUARD_TOS_TUPLE_r11 981 -#define _GUARD_TOS_TUPLE_r22 982 -#define _GUARD_TOS_TUPLE_r33 983 -#define _GUARD_TOS_UNICODE_r01 984 -#define _GUARD_TOS_UNICODE_r11 985 -#define _GUARD_TOS_UNICODE_r22 986 -#define _GUARD_TOS_UNICODE_r33 987 -#define _GUARD_TYPE_VERSION_r01 988 -#define _GUARD_TYPE_VERSION_r11 989 -#define _GUARD_TYPE_VERSION_r22 990 -#define _GUARD_TYPE_VERSION_r33 991 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 992 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 993 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 994 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 995 -#define _HANDLE_PENDING_AND_DEOPT_r00 996 -#define _HANDLE_PENDING_AND_DEOPT_r10 997 -#define _HANDLE_PENDING_AND_DEOPT_r20 998 -#define _HANDLE_PENDING_AND_DEOPT_r30 999 -#define _IMPORT_FROM_r12 1000 -#define _IMPORT_NAME_r21 1001 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1002 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1003 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1004 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1005 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1006 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1007 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1008 -#define _INSERT_1_LOAD_CONST_INLINE_r02 1009 -#define _INSERT_1_LOAD_CONST_INLINE_r12 1010 -#define _INSERT_1_LOAD_CONST_INLINE_r23 1011 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1012 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1013 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1014 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1015 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1016 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1017 -#define _INSERT_NULL_r10 1018 -#define _INSTRUMENTED_FOR_ITER_r23 1019 -#define _INSTRUMENTED_INSTRUCTION_r00 1020 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1021 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1022 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1023 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1024 -#define _INSTRUMENTED_LINE_r00 1025 -#define _INSTRUMENTED_NOT_TAKEN_r00 1026 -#define _INSTRUMENTED_NOT_TAKEN_r11 1027 -#define _INSTRUMENTED_NOT_TAKEN_r22 1028 -#define _INSTRUMENTED_NOT_TAKEN_r33 1029 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1030 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1031 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1032 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1033 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1034 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1035 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1036 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1037 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1038 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1039 -#define _IS_NONE_r11 1040 -#define _IS_OP_r03 1041 -#define _IS_OP_r13 1042 -#define _IS_OP_r23 1043 -#define _ITER_CHECK_LIST_r02 1044 -#define _ITER_CHECK_LIST_r12 1045 -#define _ITER_CHECK_LIST_r22 1046 -#define _ITER_CHECK_LIST_r33 1047 -#define _ITER_CHECK_RANGE_r02 1048 -#define _ITER_CHECK_RANGE_r12 1049 -#define _ITER_CHECK_RANGE_r22 1050 -#define _ITER_CHECK_RANGE_r33 1051 -#define _ITER_CHECK_TUPLE_r02 1052 -#define _ITER_CHECK_TUPLE_r12 1053 -#define _ITER_CHECK_TUPLE_r22 1054 -#define _ITER_CHECK_TUPLE_r33 1055 -#define _ITER_JUMP_LIST_r02 1056 -#define _ITER_JUMP_LIST_r12 1057 -#define _ITER_JUMP_LIST_r22 1058 -#define _ITER_JUMP_LIST_r33 1059 -#define _ITER_JUMP_RANGE_r02 1060 -#define _ITER_JUMP_RANGE_r12 1061 -#define _ITER_JUMP_RANGE_r22 1062 -#define _ITER_JUMP_RANGE_r33 1063 -#define _ITER_JUMP_TUPLE_r02 1064 -#define _ITER_JUMP_TUPLE_r12 1065 -#define _ITER_JUMP_TUPLE_r22 1066 -#define _ITER_JUMP_TUPLE_r33 1067 -#define _ITER_NEXT_LIST_r23 1068 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1069 -#define _ITER_NEXT_RANGE_r03 1070 -#define _ITER_NEXT_RANGE_r13 1071 -#define _ITER_NEXT_RANGE_r23 1072 -#define _ITER_NEXT_TUPLE_r03 1073 -#define _ITER_NEXT_TUPLE_r13 1074 -#define _ITER_NEXT_TUPLE_r23 1075 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1076 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1077 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1078 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1079 -#define _JUMP_TO_TOP_r00 1080 -#define _LIST_APPEND_r10 1081 -#define _LIST_EXTEND_r10 1082 -#define _LOAD_ATTR_r10 1083 -#define _LOAD_ATTR_CLASS_r11 1084 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1085 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1086 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1087 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1088 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1089 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1090 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1091 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1092 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1093 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1094 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1095 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1096 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1097 -#define _LOAD_ATTR_MODULE_r12 1098 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1099 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1100 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1101 -#define _LOAD_ATTR_SLOT_r02 1102 -#define _LOAD_ATTR_SLOT_r12 1103 -#define _LOAD_ATTR_SLOT_r23 1104 -#define _LOAD_ATTR_WITH_HINT_r12 1105 -#define _LOAD_BUILD_CLASS_r01 1106 -#define _LOAD_BYTECODE_r00 1107 -#define _LOAD_COMMON_CONSTANT_r01 1108 -#define _LOAD_COMMON_CONSTANT_r12 1109 -#define _LOAD_COMMON_CONSTANT_r23 1110 -#define _LOAD_CONST_r01 1111 -#define _LOAD_CONST_r12 1112 -#define _LOAD_CONST_r23 1113 -#define _LOAD_CONST_INLINE_r01 1114 -#define _LOAD_CONST_INLINE_r12 1115 -#define _LOAD_CONST_INLINE_r23 1116 -#define _LOAD_CONST_INLINE_BORROW_r01 1117 -#define _LOAD_CONST_INLINE_BORROW_r12 1118 -#define _LOAD_CONST_INLINE_BORROW_r23 1119 -#define _LOAD_CONST_UNDER_INLINE_r02 1120 -#define _LOAD_CONST_UNDER_INLINE_r12 1121 -#define _LOAD_CONST_UNDER_INLINE_r23 1122 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1123 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1124 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1125 -#define _LOAD_DEREF_r01 1126 -#define _LOAD_FAST_r01 1127 -#define _LOAD_FAST_r12 1128 -#define _LOAD_FAST_r23 1129 -#define _LOAD_FAST_0_r01 1130 -#define _LOAD_FAST_0_r12 1131 -#define _LOAD_FAST_0_r23 1132 -#define _LOAD_FAST_1_r01 1133 -#define _LOAD_FAST_1_r12 1134 -#define _LOAD_FAST_1_r23 1135 -#define _LOAD_FAST_2_r01 1136 -#define _LOAD_FAST_2_r12 1137 -#define _LOAD_FAST_2_r23 1138 -#define _LOAD_FAST_3_r01 1139 -#define _LOAD_FAST_3_r12 1140 -#define _LOAD_FAST_3_r23 1141 -#define _LOAD_FAST_4_r01 1142 -#define _LOAD_FAST_4_r12 1143 -#define _LOAD_FAST_4_r23 1144 -#define _LOAD_FAST_5_r01 1145 -#define _LOAD_FAST_5_r12 1146 -#define _LOAD_FAST_5_r23 1147 -#define _LOAD_FAST_6_r01 1148 -#define _LOAD_FAST_6_r12 1149 -#define _LOAD_FAST_6_r23 1150 -#define _LOAD_FAST_7_r01 1151 -#define _LOAD_FAST_7_r12 1152 -#define _LOAD_FAST_7_r23 1153 -#define _LOAD_FAST_AND_CLEAR_r01 1154 -#define _LOAD_FAST_AND_CLEAR_r12 1155 -#define _LOAD_FAST_AND_CLEAR_r23 1156 -#define _LOAD_FAST_BORROW_r01 1157 -#define _LOAD_FAST_BORROW_r12 1158 -#define _LOAD_FAST_BORROW_r23 1159 -#define _LOAD_FAST_BORROW_0_r01 1160 -#define _LOAD_FAST_BORROW_0_r12 1161 -#define _LOAD_FAST_BORROW_0_r23 1162 -#define _LOAD_FAST_BORROW_1_r01 1163 -#define _LOAD_FAST_BORROW_1_r12 1164 -#define _LOAD_FAST_BORROW_1_r23 1165 -#define _LOAD_FAST_BORROW_2_r01 1166 -#define _LOAD_FAST_BORROW_2_r12 1167 -#define _LOAD_FAST_BORROW_2_r23 1168 -#define _LOAD_FAST_BORROW_3_r01 1169 -#define _LOAD_FAST_BORROW_3_r12 1170 -#define _LOAD_FAST_BORROW_3_r23 1171 -#define _LOAD_FAST_BORROW_4_r01 1172 -#define _LOAD_FAST_BORROW_4_r12 1173 -#define _LOAD_FAST_BORROW_4_r23 1174 -#define _LOAD_FAST_BORROW_5_r01 1175 -#define _LOAD_FAST_BORROW_5_r12 1176 -#define _LOAD_FAST_BORROW_5_r23 1177 -#define _LOAD_FAST_BORROW_6_r01 1178 -#define _LOAD_FAST_BORROW_6_r12 1179 -#define _LOAD_FAST_BORROW_6_r23 1180 -#define _LOAD_FAST_BORROW_7_r01 1181 -#define _LOAD_FAST_BORROW_7_r12 1182 -#define _LOAD_FAST_BORROW_7_r23 1183 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1184 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1185 -#define _LOAD_FAST_CHECK_r01 1186 -#define _LOAD_FAST_CHECK_r12 1187 -#define _LOAD_FAST_CHECK_r23 1188 -#define _LOAD_FAST_LOAD_FAST_r02 1189 -#define _LOAD_FAST_LOAD_FAST_r13 1190 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1191 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1192 -#define _LOAD_GLOBAL_r00 1193 -#define _LOAD_GLOBAL_BUILTINS_r01 1194 -#define _LOAD_GLOBAL_MODULE_r01 1195 -#define _LOAD_LOCALS_r01 1196 -#define _LOAD_LOCALS_r12 1197 -#define _LOAD_LOCALS_r23 1198 -#define _LOAD_NAME_r01 1199 -#define _LOAD_SMALL_INT_r01 1200 -#define _LOAD_SMALL_INT_r12 1201 -#define _LOAD_SMALL_INT_r23 1202 -#define _LOAD_SMALL_INT_0_r01 1203 -#define _LOAD_SMALL_INT_0_r12 1204 -#define _LOAD_SMALL_INT_0_r23 1205 -#define _LOAD_SMALL_INT_1_r01 1206 -#define _LOAD_SMALL_INT_1_r12 1207 -#define _LOAD_SMALL_INT_1_r23 1208 -#define _LOAD_SMALL_INT_2_r01 1209 -#define _LOAD_SMALL_INT_2_r12 1210 -#define _LOAD_SMALL_INT_2_r23 1211 -#define _LOAD_SMALL_INT_3_r01 1212 -#define _LOAD_SMALL_INT_3_r12 1213 -#define _LOAD_SMALL_INT_3_r23 1214 -#define _LOAD_SPECIAL_r00 1215 -#define _LOAD_SUPER_ATTR_ATTR_r31 1216 -#define _LOAD_SUPER_ATTR_METHOD_r32 1217 -#define _MAKE_CALLARGS_A_TUPLE_r33 1218 -#define _MAKE_CELL_r00 1219 -#define _MAKE_FUNCTION_r11 1220 -#define _MAKE_WARM_r00 1221 -#define _MAKE_WARM_r11 1222 -#define _MAKE_WARM_r22 1223 -#define _MAKE_WARM_r33 1224 -#define _MAP_ADD_r20 1225 -#define _MATCH_CLASS_r31 1226 -#define _MATCH_KEYS_r23 1227 -#define _MATCH_MAPPING_r02 1228 -#define _MATCH_MAPPING_r12 1229 -#define _MATCH_MAPPING_r23 1230 -#define _MATCH_SEQUENCE_r02 1231 -#define _MATCH_SEQUENCE_r12 1232 -#define _MATCH_SEQUENCE_r23 1233 -#define _MAYBE_EXPAND_METHOD_r00 1234 -#define _MAYBE_EXPAND_METHOD_KW_r11 1235 -#define _MONITOR_CALL_r00 1236 -#define _MONITOR_CALL_KW_r11 1237 -#define _MONITOR_JUMP_BACKWARD_r00 1238 -#define _MONITOR_JUMP_BACKWARD_r11 1239 -#define _MONITOR_JUMP_BACKWARD_r22 1240 -#define _MONITOR_JUMP_BACKWARD_r33 1241 -#define _MONITOR_RESUME_r00 1242 -#define _NOP_r00 1243 -#define _NOP_r11 1244 -#define _NOP_r22 1245 -#define _NOP_r33 1246 -#define _POP_CALL_r20 1247 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1248 -#define _POP_CALL_ONE_r30 1249 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1250 -#define _POP_CALL_TWO_r30 1251 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1252 -#define _POP_EXCEPT_r10 1253 -#define _POP_ITER_r20 1254 -#define _POP_JUMP_IF_FALSE_r00 1255 -#define _POP_JUMP_IF_FALSE_r10 1256 -#define _POP_JUMP_IF_FALSE_r21 1257 -#define _POP_JUMP_IF_FALSE_r32 1258 -#define _POP_JUMP_IF_TRUE_r00 1259 -#define _POP_JUMP_IF_TRUE_r10 1260 -#define _POP_JUMP_IF_TRUE_r21 1261 -#define _POP_JUMP_IF_TRUE_r32 1262 -#define _POP_TOP_r10 1263 -#define _POP_TOP_FLOAT_r00 1264 -#define _POP_TOP_FLOAT_r10 1265 -#define _POP_TOP_FLOAT_r21 1266 -#define _POP_TOP_FLOAT_r32 1267 -#define _POP_TOP_INT_r00 1268 -#define _POP_TOP_INT_r10 1269 -#define _POP_TOP_INT_r21 1270 -#define _POP_TOP_INT_r32 1271 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1272 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1273 -#define _POP_TOP_NOP_r00 1274 -#define _POP_TOP_NOP_r10 1275 -#define _POP_TOP_NOP_r21 1276 -#define _POP_TOP_NOP_r32 1277 -#define _POP_TOP_UNICODE_r00 1278 -#define _POP_TOP_UNICODE_r10 1279 -#define _POP_TOP_UNICODE_r21 1280 -#define _POP_TOP_UNICODE_r32 1281 -#define _POP_TWO_r20 1282 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1283 -#define _PUSH_EXC_INFO_r02 1284 -#define _PUSH_EXC_INFO_r12 1285 -#define _PUSH_EXC_INFO_r23 1286 -#define _PUSH_FRAME_r10 1287 -#define _PUSH_NULL_r01 1288 -#define _PUSH_NULL_r12 1289 -#define _PUSH_NULL_r23 1290 -#define _PUSH_NULL_CONDITIONAL_r00 1291 -#define _PY_FRAME_EX_r31 1292 -#define _PY_FRAME_GENERAL_r01 1293 -#define _PY_FRAME_KW_r11 1294 -#define _QUICKEN_RESUME_r00 1295 -#define _QUICKEN_RESUME_r11 1296 -#define _QUICKEN_RESUME_r22 1297 -#define _QUICKEN_RESUME_r33 1298 -#define _REPLACE_WITH_TRUE_r02 1299 -#define _REPLACE_WITH_TRUE_r12 1300 -#define _REPLACE_WITH_TRUE_r23 1301 -#define _RESUME_CHECK_r00 1302 -#define _RESUME_CHECK_r11 1303 -#define _RESUME_CHECK_r22 1304 -#define _RESUME_CHECK_r33 1305 -#define _RETURN_GENERATOR_r01 1306 -#define _RETURN_VALUE_r11 1307 -#define _SAVE_RETURN_OFFSET_r00 1308 -#define _SAVE_RETURN_OFFSET_r11 1309 -#define _SAVE_RETURN_OFFSET_r22 1310 -#define _SAVE_RETURN_OFFSET_r33 1311 -#define _SEND_r22 1312 -#define _SEND_GEN_FRAME_r22 1313 -#define _SETUP_ANNOTATIONS_r00 1314 -#define _SET_ADD_r10 1315 -#define _SET_FUNCTION_ATTRIBUTE_r01 1316 -#define _SET_FUNCTION_ATTRIBUTE_r11 1317 -#define _SET_FUNCTION_ATTRIBUTE_r21 1318 -#define _SET_FUNCTION_ATTRIBUTE_r32 1319 -#define _SET_IP_r00 1320 -#define _SET_IP_r11 1321 -#define _SET_IP_r22 1322 -#define _SET_IP_r33 1323 -#define _SET_UPDATE_r10 1324 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1325 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1326 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1327 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1328 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1329 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1330 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1331 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1332 -#define _SPILL_OR_RELOAD_r01 1333 -#define _SPILL_OR_RELOAD_r02 1334 -#define _SPILL_OR_RELOAD_r03 1335 -#define _SPILL_OR_RELOAD_r10 1336 -#define _SPILL_OR_RELOAD_r12 1337 -#define _SPILL_OR_RELOAD_r13 1338 -#define _SPILL_OR_RELOAD_r20 1339 -#define _SPILL_OR_RELOAD_r21 1340 -#define _SPILL_OR_RELOAD_r23 1341 -#define _SPILL_OR_RELOAD_r30 1342 -#define _SPILL_OR_RELOAD_r31 1343 -#define _SPILL_OR_RELOAD_r32 1344 -#define _START_EXECUTOR_r00 1345 -#define _STORE_ATTR_r20 1346 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1347 -#define _STORE_ATTR_INSTANCE_VALUE_NULL_r01 1348 -#define _STORE_ATTR_INSTANCE_VALUE_NULL_r11 1349 -#define _STORE_ATTR_INSTANCE_VALUE_NULL_r21 1350 -#define _STORE_ATTR_INSTANCE_VALUE_NULL_r32 1351 -#define _STORE_ATTR_SLOT_r21 1352 -#define _STORE_ATTR_SLOT_NULL_r01 1353 -#define _STORE_ATTR_SLOT_NULL_r11 1354 -#define _STORE_ATTR_SLOT_NULL_r21 1355 -#define _STORE_ATTR_SLOT_NULL_r32 1356 -#define _STORE_ATTR_WITH_HINT_r21 1357 -#define _STORE_DEREF_r10 1358 -#define _STORE_FAST_LOAD_FAST_r11 1359 -#define _STORE_FAST_STORE_FAST_r20 1360 -#define _STORE_GLOBAL_r10 1361 -#define _STORE_NAME_r10 1362 -#define _STORE_SLICE_r30 1363 -#define _STORE_SUBSCR_r30 1364 -#define _STORE_SUBSCR_DICT_r31 1365 -#define _STORE_SUBSCR_LIST_INT_r32 1366 -#define _SWAP_r11 1367 -#define _SWAP_2_r02 1368 -#define _SWAP_2_r12 1369 -#define _SWAP_2_r22 1370 -#define _SWAP_2_r33 1371 -#define _SWAP_3_r03 1372 -#define _SWAP_3_r13 1373 -#define _SWAP_3_r23 1374 -#define _SWAP_3_r33 1375 -#define _SWAP_FAST_r01 1376 -#define _SWAP_FAST_r11 1377 -#define _SWAP_FAST_r22 1378 -#define _SWAP_FAST_r33 1379 -#define _SWAP_FAST_0_r01 1380 -#define _SWAP_FAST_0_r11 1381 -#define _SWAP_FAST_0_r22 1382 -#define _SWAP_FAST_0_r33 1383 -#define _SWAP_FAST_1_r01 1384 -#define _SWAP_FAST_1_r11 1385 -#define _SWAP_FAST_1_r22 1386 -#define _SWAP_FAST_1_r33 1387 -#define _SWAP_FAST_2_r01 1388 -#define _SWAP_FAST_2_r11 1389 -#define _SWAP_FAST_2_r22 1390 -#define _SWAP_FAST_2_r33 1391 -#define _SWAP_FAST_3_r01 1392 -#define _SWAP_FAST_3_r11 1393 -#define _SWAP_FAST_3_r22 1394 -#define _SWAP_FAST_3_r33 1395 -#define _SWAP_FAST_4_r01 1396 -#define _SWAP_FAST_4_r11 1397 -#define _SWAP_FAST_4_r22 1398 -#define _SWAP_FAST_4_r33 1399 -#define _SWAP_FAST_5_r01 1400 -#define _SWAP_FAST_5_r11 1401 -#define _SWAP_FAST_5_r22 1402 -#define _SWAP_FAST_5_r33 1403 -#define _SWAP_FAST_6_r01 1404 -#define _SWAP_FAST_6_r11 1405 -#define _SWAP_FAST_6_r22 1406 -#define _SWAP_FAST_6_r33 1407 -#define _SWAP_FAST_7_r01 1408 -#define _SWAP_FAST_7_r11 1409 -#define _SWAP_FAST_7_r22 1410 -#define _SWAP_FAST_7_r33 1411 -#define _TIER2_RESUME_CHECK_r00 1412 -#define _TIER2_RESUME_CHECK_r11 1413 -#define _TIER2_RESUME_CHECK_r22 1414 -#define _TIER2_RESUME_CHECK_r33 1415 -#define _TO_BOOL_r11 1416 -#define _TO_BOOL_BOOL_r01 1417 -#define _TO_BOOL_BOOL_r11 1418 -#define _TO_BOOL_BOOL_r22 1419 -#define _TO_BOOL_BOOL_r33 1420 -#define _TO_BOOL_INT_r02 1421 -#define _TO_BOOL_INT_r12 1422 -#define _TO_BOOL_INT_r23 1423 -#define _TO_BOOL_LIST_r02 1424 -#define _TO_BOOL_LIST_r12 1425 -#define _TO_BOOL_LIST_r23 1426 -#define _TO_BOOL_NONE_r01 1427 -#define _TO_BOOL_NONE_r11 1428 -#define _TO_BOOL_NONE_r22 1429 -#define _TO_BOOL_NONE_r33 1430 -#define _TO_BOOL_STR_r02 1431 -#define _TO_BOOL_STR_r12 1432 -#define _TO_BOOL_STR_r23 1433 -#define _TRACE_RECORD_r00 1434 -#define _UNARY_INVERT_r12 1435 -#define _UNARY_NEGATIVE_r12 1436 -#define _UNARY_NOT_r01 1437 -#define _UNARY_NOT_r11 1438 -#define _UNARY_NOT_r22 1439 -#define _UNARY_NOT_r33 1440 -#define _UNPACK_EX_r10 1441 -#define _UNPACK_SEQUENCE_r10 1442 -#define _UNPACK_SEQUENCE_LIST_r10 1443 -#define _UNPACK_SEQUENCE_TUPLE_r10 1444 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1445 -#define _WITH_EXCEPT_START_r33 1446 -#define _YIELD_VALUE_r11 1447 -#define MAX_UOP_REGS_ID 1447 +#define MAX_UOP_ID 579 +#define _BINARY_OP_r23 580 +#define _BINARY_OP_ADD_FLOAT_r03 581 +#define _BINARY_OP_ADD_FLOAT_r13 582 +#define _BINARY_OP_ADD_FLOAT_r23 583 +#define _BINARY_OP_ADD_INT_r03 584 +#define _BINARY_OP_ADD_INT_r13 585 +#define _BINARY_OP_ADD_INT_r23 586 +#define _BINARY_OP_ADD_UNICODE_r03 587 +#define _BINARY_OP_ADD_UNICODE_r13 588 +#define _BINARY_OP_ADD_UNICODE_r23 589 +#define _BINARY_OP_EXTEND_r23 590 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 591 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 592 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 593 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 594 +#define _BINARY_OP_MULTIPLY_INT_r03 595 +#define _BINARY_OP_MULTIPLY_INT_r13 596 +#define _BINARY_OP_MULTIPLY_INT_r23 597 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 598 +#define _BINARY_OP_SUBSCR_DICT_r23 599 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 600 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 601 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 602 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 603 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 604 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 605 +#define _BINARY_OP_SUBSCR_STR_INT_r23 606 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 607 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 608 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 609 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 610 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 611 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 612 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 613 +#define _BINARY_OP_SUBTRACT_INT_r03 614 +#define _BINARY_OP_SUBTRACT_INT_r13 615 +#define _BINARY_OP_SUBTRACT_INT_r23 616 +#define _BINARY_SLICE_r31 617 +#define _BUILD_INTERPOLATION_r01 618 +#define _BUILD_LIST_r01 619 +#define _BUILD_MAP_r01 620 +#define _BUILD_SET_r01 621 +#define _BUILD_SLICE_r01 622 +#define _BUILD_STRING_r01 623 +#define _BUILD_TEMPLATE_r21 624 +#define _BUILD_TUPLE_r01 625 +#define _CALL_BUILTIN_CLASS_r01 626 +#define _CALL_BUILTIN_FAST_r01 627 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 628 +#define _CALL_BUILTIN_O_r03 629 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 630 +#define _CALL_INTRINSIC_1_r11 631 +#define _CALL_INTRINSIC_2_r21 632 +#define _CALL_ISINSTANCE_r31 633 +#define _CALL_KW_NON_PY_r11 634 +#define _CALL_LEN_r33 635 +#define _CALL_LIST_APPEND_r03 636 +#define _CALL_LIST_APPEND_r13 637 +#define _CALL_LIST_APPEND_r23 638 +#define _CALL_LIST_APPEND_r33 639 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 640 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 641 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 642 +#define _CALL_METHOD_DESCRIPTOR_O_r03 643 +#define _CALL_NON_PY_GENERAL_r01 644 +#define _CALL_STR_1_r32 645 +#define _CALL_TUPLE_1_r32 646 +#define _CALL_TYPE_1_r02 647 +#define _CALL_TYPE_1_r12 648 +#define _CALL_TYPE_1_r22 649 +#define _CALL_TYPE_1_r32 650 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 651 +#define _CHECK_ATTR_CLASS_r01 652 +#define _CHECK_ATTR_CLASS_r11 653 +#define _CHECK_ATTR_CLASS_r22 654 +#define _CHECK_ATTR_CLASS_r33 655 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 656 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 657 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 658 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 659 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 660 +#define _CHECK_EG_MATCH_r22 661 +#define _CHECK_EXC_MATCH_r22 662 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 663 +#define _CHECK_FUNCTION_VERSION_r00 664 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 665 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 666 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 667 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 668 +#define _CHECK_FUNCTION_VERSION_KW_r11 669 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 670 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 671 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 672 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 673 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 674 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 675 +#define _CHECK_IS_PY_CALLABLE_EX_r03 676 +#define _CHECK_IS_PY_CALLABLE_EX_r13 677 +#define _CHECK_IS_PY_CALLABLE_EX_r23 678 +#define _CHECK_IS_PY_CALLABLE_EX_r33 679 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 680 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 681 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 682 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 683 +#define _CHECK_METHOD_VERSION_r00 684 +#define _CHECK_METHOD_VERSION_KW_r11 685 +#define _CHECK_PEP_523_r00 686 +#define _CHECK_PEP_523_r11 687 +#define _CHECK_PEP_523_r22 688 +#define _CHECK_PEP_523_r33 689 +#define _CHECK_PERIODIC_r00 690 +#define _CHECK_PERIODIC_AT_END_r00 691 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 692 +#define _CHECK_RECURSION_REMAINING_r00 693 +#define _CHECK_RECURSION_REMAINING_r11 694 +#define _CHECK_RECURSION_REMAINING_r22 695 +#define _CHECK_RECURSION_REMAINING_r33 696 +#define _CHECK_STACK_SPACE_r00 697 +#define _CHECK_STACK_SPACE_OPERAND_r00 698 +#define _CHECK_STACK_SPACE_OPERAND_r11 699 +#define _CHECK_STACK_SPACE_OPERAND_r22 700 +#define _CHECK_STACK_SPACE_OPERAND_r33 701 +#define _CHECK_VALIDITY_r00 702 +#define _CHECK_VALIDITY_r11 703 +#define _CHECK_VALIDITY_r22 704 +#define _CHECK_VALIDITY_r33 705 +#define _COLD_DYNAMIC_EXIT_r00 706 +#define _COLD_EXIT_r00 707 +#define _COMPARE_OP_r21 708 +#define _COMPARE_OP_FLOAT_r03 709 +#define _COMPARE_OP_FLOAT_r13 710 +#define _COMPARE_OP_FLOAT_r23 711 +#define _COMPARE_OP_INT_r23 712 +#define _COMPARE_OP_STR_r23 713 +#define _CONTAINS_OP_r23 714 +#define _CONTAINS_OP_DICT_r23 715 +#define _CONTAINS_OP_SET_r23 716 +#define _CONVERT_VALUE_r11 717 +#define _COPY_r01 718 +#define _COPY_1_r02 719 +#define _COPY_1_r12 720 +#define _COPY_1_r23 721 +#define _COPY_2_r03 722 +#define _COPY_2_r13 723 +#define _COPY_2_r23 724 +#define _COPY_3_r03 725 +#define _COPY_3_r13 726 +#define _COPY_3_r23 727 +#define _COPY_3_r33 728 +#define _COPY_FREE_VARS_r00 729 +#define _COPY_FREE_VARS_r11 730 +#define _COPY_FREE_VARS_r22 731 +#define _COPY_FREE_VARS_r33 732 +#define _CREATE_INIT_FRAME_r01 733 +#define _DELETE_ATTR_r10 734 +#define _DELETE_DEREF_r00 735 +#define _DELETE_FAST_r00 736 +#define _DELETE_GLOBAL_r00 737 +#define _DELETE_NAME_r00 738 +#define _DELETE_SUBSCR_r20 739 +#define _DEOPT_r00 740 +#define _DEOPT_r10 741 +#define _DEOPT_r20 742 +#define _DEOPT_r30 743 +#define _DICT_MERGE_r10 744 +#define _DICT_UPDATE_r10 745 +#define _DO_CALL_r01 746 +#define _DO_CALL_FUNCTION_EX_r31 747 +#define _DO_CALL_KW_r11 748 +#define _DYNAMIC_EXIT_r00 749 +#define _DYNAMIC_EXIT_r10 750 +#define _DYNAMIC_EXIT_r20 751 +#define _DYNAMIC_EXIT_r30 752 +#define _END_FOR_r10 753 +#define _END_SEND_r21 754 +#define _ERROR_POP_N_r00 755 +#define _EXIT_INIT_CHECK_r10 756 +#define _EXIT_TRACE_r00 757 +#define _EXIT_TRACE_r10 758 +#define _EXIT_TRACE_r20 759 +#define _EXIT_TRACE_r30 760 +#define _EXPAND_METHOD_r00 761 +#define _EXPAND_METHOD_KW_r11 762 +#define _FATAL_ERROR_r00 763 +#define _FATAL_ERROR_r11 764 +#define _FATAL_ERROR_r22 765 +#define _FATAL_ERROR_r33 766 +#define _FORMAT_SIMPLE_r11 767 +#define _FORMAT_WITH_SPEC_r21 768 +#define _FOR_ITER_r23 769 +#define _FOR_ITER_GEN_FRAME_r03 770 +#define _FOR_ITER_GEN_FRAME_r13 771 +#define _FOR_ITER_GEN_FRAME_r23 772 +#define _FOR_ITER_TIER_TWO_r23 773 +#define _GET_AITER_r11 774 +#define _GET_ANEXT_r12 775 +#define _GET_AWAITABLE_r11 776 +#define _GET_ITER_r12 777 +#define _GET_LEN_r12 778 +#define _GET_YIELD_FROM_ITER_r11 779 +#define _GUARD_BINARY_OP_EXTEND_r22 780 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 781 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 782 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 783 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 784 +#define _GUARD_BIT_IS_SET_POP_r00 785 +#define _GUARD_BIT_IS_SET_POP_r10 786 +#define _GUARD_BIT_IS_SET_POP_r21 787 +#define _GUARD_BIT_IS_SET_POP_r32 788 +#define _GUARD_BIT_IS_SET_POP_4_r00 789 +#define _GUARD_BIT_IS_SET_POP_4_r10 790 +#define _GUARD_BIT_IS_SET_POP_4_r21 791 +#define _GUARD_BIT_IS_SET_POP_4_r32 792 +#define _GUARD_BIT_IS_SET_POP_5_r00 793 +#define _GUARD_BIT_IS_SET_POP_5_r10 794 +#define _GUARD_BIT_IS_SET_POP_5_r21 795 +#define _GUARD_BIT_IS_SET_POP_5_r32 796 +#define _GUARD_BIT_IS_SET_POP_6_r00 797 +#define _GUARD_BIT_IS_SET_POP_6_r10 798 +#define _GUARD_BIT_IS_SET_POP_6_r21 799 +#define _GUARD_BIT_IS_SET_POP_6_r32 800 +#define _GUARD_BIT_IS_SET_POP_7_r00 801 +#define _GUARD_BIT_IS_SET_POP_7_r10 802 +#define _GUARD_BIT_IS_SET_POP_7_r21 803 +#define _GUARD_BIT_IS_SET_POP_7_r32 804 +#define _GUARD_BIT_IS_UNSET_POP_r00 805 +#define _GUARD_BIT_IS_UNSET_POP_r10 806 +#define _GUARD_BIT_IS_UNSET_POP_r21 807 +#define _GUARD_BIT_IS_UNSET_POP_r32 808 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 809 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 810 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 811 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 812 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 813 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 814 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 815 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 816 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 817 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 818 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 819 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 820 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 821 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 822 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 823 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 824 +#define _GUARD_CALLABLE_ISINSTANCE_r03 825 +#define _GUARD_CALLABLE_ISINSTANCE_r13 826 +#define _GUARD_CALLABLE_ISINSTANCE_r23 827 +#define _GUARD_CALLABLE_ISINSTANCE_r33 828 +#define _GUARD_CALLABLE_LEN_r03 829 +#define _GUARD_CALLABLE_LEN_r13 830 +#define _GUARD_CALLABLE_LEN_r23 831 +#define _GUARD_CALLABLE_LEN_r33 832 +#define _GUARD_CALLABLE_LIST_APPEND_r03 833 +#define _GUARD_CALLABLE_LIST_APPEND_r13 834 +#define _GUARD_CALLABLE_LIST_APPEND_r23 835 +#define _GUARD_CALLABLE_LIST_APPEND_r33 836 +#define _GUARD_CALLABLE_STR_1_r03 837 +#define _GUARD_CALLABLE_STR_1_r13 838 +#define _GUARD_CALLABLE_STR_1_r23 839 +#define _GUARD_CALLABLE_STR_1_r33 840 +#define _GUARD_CALLABLE_TUPLE_1_r03 841 +#define _GUARD_CALLABLE_TUPLE_1_r13 842 +#define _GUARD_CALLABLE_TUPLE_1_r23 843 +#define _GUARD_CALLABLE_TUPLE_1_r33 844 +#define _GUARD_CALLABLE_TYPE_1_r03 845 +#define _GUARD_CALLABLE_TYPE_1_r13 846 +#define _GUARD_CALLABLE_TYPE_1_r23 847 +#define _GUARD_CALLABLE_TYPE_1_r33 848 +#define _GUARD_DORV_NO_DICT_r01 849 +#define _GUARD_DORV_NO_DICT_r11 850 +#define _GUARD_DORV_NO_DICT_r22 851 +#define _GUARD_DORV_NO_DICT_r33 852 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 853 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 854 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 855 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 856 +#define _GUARD_GLOBALS_VERSION_r00 857 +#define _GUARD_GLOBALS_VERSION_r11 858 +#define _GUARD_GLOBALS_VERSION_r22 859 +#define _GUARD_GLOBALS_VERSION_r33 860 +#define _GUARD_IP_RETURN_GENERATOR_r00 861 +#define _GUARD_IP_RETURN_GENERATOR_r11 862 +#define _GUARD_IP_RETURN_GENERATOR_r22 863 +#define _GUARD_IP_RETURN_GENERATOR_r33 864 +#define _GUARD_IP_RETURN_VALUE_r00 865 +#define _GUARD_IP_RETURN_VALUE_r11 866 +#define _GUARD_IP_RETURN_VALUE_r22 867 +#define _GUARD_IP_RETURN_VALUE_r33 868 +#define _GUARD_IP_YIELD_VALUE_r00 869 +#define _GUARD_IP_YIELD_VALUE_r11 870 +#define _GUARD_IP_YIELD_VALUE_r22 871 +#define _GUARD_IP_YIELD_VALUE_r33 872 +#define _GUARD_IP__PUSH_FRAME_r00 873 +#define _GUARD_IP__PUSH_FRAME_r11 874 +#define _GUARD_IP__PUSH_FRAME_r22 875 +#define _GUARD_IP__PUSH_FRAME_r33 876 +#define _GUARD_IS_FALSE_POP_r00 877 +#define _GUARD_IS_FALSE_POP_r10 878 +#define _GUARD_IS_FALSE_POP_r21 879 +#define _GUARD_IS_FALSE_POP_r32 880 +#define _GUARD_IS_NONE_POP_r00 881 +#define _GUARD_IS_NONE_POP_r10 882 +#define _GUARD_IS_NONE_POP_r21 883 +#define _GUARD_IS_NONE_POP_r32 884 +#define _GUARD_IS_NOT_NONE_POP_r10 885 +#define _GUARD_IS_TRUE_POP_r00 886 +#define _GUARD_IS_TRUE_POP_r10 887 +#define _GUARD_IS_TRUE_POP_r21 888 +#define _GUARD_IS_TRUE_POP_r32 889 +#define _GUARD_KEYS_VERSION_r01 890 +#define _GUARD_KEYS_VERSION_r11 891 +#define _GUARD_KEYS_VERSION_r22 892 +#define _GUARD_KEYS_VERSION_r33 893 +#define _GUARD_NOS_COMPACT_ASCII_r02 894 +#define _GUARD_NOS_COMPACT_ASCII_r12 895 +#define _GUARD_NOS_COMPACT_ASCII_r22 896 +#define _GUARD_NOS_COMPACT_ASCII_r33 897 +#define _GUARD_NOS_DICT_r02 898 +#define _GUARD_NOS_DICT_r12 899 +#define _GUARD_NOS_DICT_r22 900 +#define _GUARD_NOS_DICT_r33 901 +#define _GUARD_NOS_FLOAT_r02 902 +#define _GUARD_NOS_FLOAT_r12 903 +#define _GUARD_NOS_FLOAT_r22 904 +#define _GUARD_NOS_FLOAT_r33 905 +#define _GUARD_NOS_INT_r02 906 +#define _GUARD_NOS_INT_r12 907 +#define _GUARD_NOS_INT_r22 908 +#define _GUARD_NOS_INT_r33 909 +#define _GUARD_NOS_LIST_r02 910 +#define _GUARD_NOS_LIST_r12 911 +#define _GUARD_NOS_LIST_r22 912 +#define _GUARD_NOS_LIST_r33 913 +#define _GUARD_NOS_NOT_NULL_r02 914 +#define _GUARD_NOS_NOT_NULL_r12 915 +#define _GUARD_NOS_NOT_NULL_r22 916 +#define _GUARD_NOS_NOT_NULL_r33 917 +#define _GUARD_NOS_NULL_r02 918 +#define _GUARD_NOS_NULL_r12 919 +#define _GUARD_NOS_NULL_r22 920 +#define _GUARD_NOS_NULL_r33 921 +#define _GUARD_NOS_OVERFLOWED_r02 922 +#define _GUARD_NOS_OVERFLOWED_r12 923 +#define _GUARD_NOS_OVERFLOWED_r22 924 +#define _GUARD_NOS_OVERFLOWED_r33 925 +#define _GUARD_NOS_TUPLE_r02 926 +#define _GUARD_NOS_TUPLE_r12 927 +#define _GUARD_NOS_TUPLE_r22 928 +#define _GUARD_NOS_TUPLE_r33 929 +#define _GUARD_NOS_UNICODE_r02 930 +#define _GUARD_NOS_UNICODE_r12 931 +#define _GUARD_NOS_UNICODE_r22 932 +#define _GUARD_NOS_UNICODE_r33 933 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 934 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 935 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 936 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 937 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 938 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 939 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 940 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 941 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 942 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 943 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 944 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 945 +#define _GUARD_THIRD_NULL_r03 946 +#define _GUARD_THIRD_NULL_r13 947 +#define _GUARD_THIRD_NULL_r23 948 +#define _GUARD_THIRD_NULL_r33 949 +#define _GUARD_TOS_ANY_SET_r01 950 +#define _GUARD_TOS_ANY_SET_r11 951 +#define _GUARD_TOS_ANY_SET_r22 952 +#define _GUARD_TOS_ANY_SET_r33 953 +#define _GUARD_TOS_DICT_r01 954 +#define _GUARD_TOS_DICT_r11 955 +#define _GUARD_TOS_DICT_r22 956 +#define _GUARD_TOS_DICT_r33 957 +#define _GUARD_TOS_FLOAT_r01 958 +#define _GUARD_TOS_FLOAT_r11 959 +#define _GUARD_TOS_FLOAT_r22 960 +#define _GUARD_TOS_FLOAT_r33 961 +#define _GUARD_TOS_INT_r01 962 +#define _GUARD_TOS_INT_r11 963 +#define _GUARD_TOS_INT_r22 964 +#define _GUARD_TOS_INT_r33 965 +#define _GUARD_TOS_LIST_r01 966 +#define _GUARD_TOS_LIST_r11 967 +#define _GUARD_TOS_LIST_r22 968 +#define _GUARD_TOS_LIST_r33 969 +#define _GUARD_TOS_OVERFLOWED_r01 970 +#define _GUARD_TOS_OVERFLOWED_r11 971 +#define _GUARD_TOS_OVERFLOWED_r22 972 +#define _GUARD_TOS_OVERFLOWED_r33 973 +#define _GUARD_TOS_SLICE_r01 974 +#define _GUARD_TOS_SLICE_r11 975 +#define _GUARD_TOS_SLICE_r22 976 +#define _GUARD_TOS_SLICE_r33 977 +#define _GUARD_TOS_TUPLE_r01 978 +#define _GUARD_TOS_TUPLE_r11 979 +#define _GUARD_TOS_TUPLE_r22 980 +#define _GUARD_TOS_TUPLE_r33 981 +#define _GUARD_TOS_UNICODE_r01 982 +#define _GUARD_TOS_UNICODE_r11 983 +#define _GUARD_TOS_UNICODE_r22 984 +#define _GUARD_TOS_UNICODE_r33 985 +#define _GUARD_TYPE_VERSION_r01 986 +#define _GUARD_TYPE_VERSION_r11 987 +#define _GUARD_TYPE_VERSION_r22 988 +#define _GUARD_TYPE_VERSION_r33 989 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 990 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 991 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 992 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 993 +#define _HANDLE_PENDING_AND_DEOPT_r00 994 +#define _HANDLE_PENDING_AND_DEOPT_r10 995 +#define _HANDLE_PENDING_AND_DEOPT_r20 996 +#define _HANDLE_PENDING_AND_DEOPT_r30 997 +#define _IMPORT_FROM_r12 998 +#define _IMPORT_NAME_r21 999 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1000 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1001 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1002 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1003 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1004 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1005 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1006 +#define _INSERT_1_LOAD_CONST_INLINE_r02 1007 +#define _INSERT_1_LOAD_CONST_INLINE_r12 1008 +#define _INSERT_1_LOAD_CONST_INLINE_r23 1009 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1010 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1011 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1012 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1013 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1014 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1015 +#define _INSERT_NULL_r10 1016 +#define _INSTRUMENTED_FOR_ITER_r23 1017 +#define _INSTRUMENTED_INSTRUCTION_r00 1018 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1019 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1020 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1021 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1022 +#define _INSTRUMENTED_LINE_r00 1023 +#define _INSTRUMENTED_NOT_TAKEN_r00 1024 +#define _INSTRUMENTED_NOT_TAKEN_r11 1025 +#define _INSTRUMENTED_NOT_TAKEN_r22 1026 +#define _INSTRUMENTED_NOT_TAKEN_r33 1027 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1028 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1029 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1030 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1031 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1032 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1033 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1034 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1035 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1036 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1037 +#define _IS_NONE_r11 1038 +#define _IS_OP_r03 1039 +#define _IS_OP_r13 1040 +#define _IS_OP_r23 1041 +#define _ITER_CHECK_LIST_r02 1042 +#define _ITER_CHECK_LIST_r12 1043 +#define _ITER_CHECK_LIST_r22 1044 +#define _ITER_CHECK_LIST_r33 1045 +#define _ITER_CHECK_RANGE_r02 1046 +#define _ITER_CHECK_RANGE_r12 1047 +#define _ITER_CHECK_RANGE_r22 1048 +#define _ITER_CHECK_RANGE_r33 1049 +#define _ITER_CHECK_TUPLE_r02 1050 +#define _ITER_CHECK_TUPLE_r12 1051 +#define _ITER_CHECK_TUPLE_r22 1052 +#define _ITER_CHECK_TUPLE_r33 1053 +#define _ITER_JUMP_LIST_r02 1054 +#define _ITER_JUMP_LIST_r12 1055 +#define _ITER_JUMP_LIST_r22 1056 +#define _ITER_JUMP_LIST_r33 1057 +#define _ITER_JUMP_RANGE_r02 1058 +#define _ITER_JUMP_RANGE_r12 1059 +#define _ITER_JUMP_RANGE_r22 1060 +#define _ITER_JUMP_RANGE_r33 1061 +#define _ITER_JUMP_TUPLE_r02 1062 +#define _ITER_JUMP_TUPLE_r12 1063 +#define _ITER_JUMP_TUPLE_r22 1064 +#define _ITER_JUMP_TUPLE_r33 1065 +#define _ITER_NEXT_LIST_r23 1066 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1067 +#define _ITER_NEXT_RANGE_r03 1068 +#define _ITER_NEXT_RANGE_r13 1069 +#define _ITER_NEXT_RANGE_r23 1070 +#define _ITER_NEXT_TUPLE_r03 1071 +#define _ITER_NEXT_TUPLE_r13 1072 +#define _ITER_NEXT_TUPLE_r23 1073 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1074 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1075 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1076 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1077 +#define _JUMP_TO_TOP_r00 1078 +#define _LIST_APPEND_r10 1079 +#define _LIST_EXTEND_r10 1080 +#define _LOAD_ATTR_r10 1081 +#define _LOAD_ATTR_CLASS_r11 1082 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1083 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1084 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1085 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1086 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1087 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1088 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1089 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1090 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1091 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1092 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1093 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1094 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1095 +#define _LOAD_ATTR_MODULE_r12 1096 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1097 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1098 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1099 +#define _LOAD_ATTR_SLOT_r02 1100 +#define _LOAD_ATTR_SLOT_r12 1101 +#define _LOAD_ATTR_SLOT_r23 1102 +#define _LOAD_ATTR_WITH_HINT_r12 1103 +#define _LOAD_BUILD_CLASS_r01 1104 +#define _LOAD_BYTECODE_r00 1105 +#define _LOAD_COMMON_CONSTANT_r01 1106 +#define _LOAD_COMMON_CONSTANT_r12 1107 +#define _LOAD_COMMON_CONSTANT_r23 1108 +#define _LOAD_CONST_r01 1109 +#define _LOAD_CONST_r12 1110 +#define _LOAD_CONST_r23 1111 +#define _LOAD_CONST_INLINE_r01 1112 +#define _LOAD_CONST_INLINE_r12 1113 +#define _LOAD_CONST_INLINE_r23 1114 +#define _LOAD_CONST_INLINE_BORROW_r01 1115 +#define _LOAD_CONST_INLINE_BORROW_r12 1116 +#define _LOAD_CONST_INLINE_BORROW_r23 1117 +#define _LOAD_CONST_UNDER_INLINE_r02 1118 +#define _LOAD_CONST_UNDER_INLINE_r12 1119 +#define _LOAD_CONST_UNDER_INLINE_r23 1120 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1121 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1122 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1123 +#define _LOAD_DEREF_r01 1124 +#define _LOAD_FAST_r01 1125 +#define _LOAD_FAST_r12 1126 +#define _LOAD_FAST_r23 1127 +#define _LOAD_FAST_0_r01 1128 +#define _LOAD_FAST_0_r12 1129 +#define _LOAD_FAST_0_r23 1130 +#define _LOAD_FAST_1_r01 1131 +#define _LOAD_FAST_1_r12 1132 +#define _LOAD_FAST_1_r23 1133 +#define _LOAD_FAST_2_r01 1134 +#define _LOAD_FAST_2_r12 1135 +#define _LOAD_FAST_2_r23 1136 +#define _LOAD_FAST_3_r01 1137 +#define _LOAD_FAST_3_r12 1138 +#define _LOAD_FAST_3_r23 1139 +#define _LOAD_FAST_4_r01 1140 +#define _LOAD_FAST_4_r12 1141 +#define _LOAD_FAST_4_r23 1142 +#define _LOAD_FAST_5_r01 1143 +#define _LOAD_FAST_5_r12 1144 +#define _LOAD_FAST_5_r23 1145 +#define _LOAD_FAST_6_r01 1146 +#define _LOAD_FAST_6_r12 1147 +#define _LOAD_FAST_6_r23 1148 +#define _LOAD_FAST_7_r01 1149 +#define _LOAD_FAST_7_r12 1150 +#define _LOAD_FAST_7_r23 1151 +#define _LOAD_FAST_AND_CLEAR_r01 1152 +#define _LOAD_FAST_AND_CLEAR_r12 1153 +#define _LOAD_FAST_AND_CLEAR_r23 1154 +#define _LOAD_FAST_BORROW_r01 1155 +#define _LOAD_FAST_BORROW_r12 1156 +#define _LOAD_FAST_BORROW_r23 1157 +#define _LOAD_FAST_BORROW_0_r01 1158 +#define _LOAD_FAST_BORROW_0_r12 1159 +#define _LOAD_FAST_BORROW_0_r23 1160 +#define _LOAD_FAST_BORROW_1_r01 1161 +#define _LOAD_FAST_BORROW_1_r12 1162 +#define _LOAD_FAST_BORROW_1_r23 1163 +#define _LOAD_FAST_BORROW_2_r01 1164 +#define _LOAD_FAST_BORROW_2_r12 1165 +#define _LOAD_FAST_BORROW_2_r23 1166 +#define _LOAD_FAST_BORROW_3_r01 1167 +#define _LOAD_FAST_BORROW_3_r12 1168 +#define _LOAD_FAST_BORROW_3_r23 1169 +#define _LOAD_FAST_BORROW_4_r01 1170 +#define _LOAD_FAST_BORROW_4_r12 1171 +#define _LOAD_FAST_BORROW_4_r23 1172 +#define _LOAD_FAST_BORROW_5_r01 1173 +#define _LOAD_FAST_BORROW_5_r12 1174 +#define _LOAD_FAST_BORROW_5_r23 1175 +#define _LOAD_FAST_BORROW_6_r01 1176 +#define _LOAD_FAST_BORROW_6_r12 1177 +#define _LOAD_FAST_BORROW_6_r23 1178 +#define _LOAD_FAST_BORROW_7_r01 1179 +#define _LOAD_FAST_BORROW_7_r12 1180 +#define _LOAD_FAST_BORROW_7_r23 1181 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1182 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1183 +#define _LOAD_FAST_CHECK_r01 1184 +#define _LOAD_FAST_CHECK_r12 1185 +#define _LOAD_FAST_CHECK_r23 1186 +#define _LOAD_FAST_LOAD_FAST_r02 1187 +#define _LOAD_FAST_LOAD_FAST_r13 1188 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1189 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1190 +#define _LOAD_GLOBAL_r00 1191 +#define _LOAD_GLOBAL_BUILTINS_r01 1192 +#define _LOAD_GLOBAL_MODULE_r01 1193 +#define _LOAD_LOCALS_r01 1194 +#define _LOAD_LOCALS_r12 1195 +#define _LOAD_LOCALS_r23 1196 +#define _LOAD_NAME_r01 1197 +#define _LOAD_SMALL_INT_r01 1198 +#define _LOAD_SMALL_INT_r12 1199 +#define _LOAD_SMALL_INT_r23 1200 +#define _LOAD_SMALL_INT_0_r01 1201 +#define _LOAD_SMALL_INT_0_r12 1202 +#define _LOAD_SMALL_INT_0_r23 1203 +#define _LOAD_SMALL_INT_1_r01 1204 +#define _LOAD_SMALL_INT_1_r12 1205 +#define _LOAD_SMALL_INT_1_r23 1206 +#define _LOAD_SMALL_INT_2_r01 1207 +#define _LOAD_SMALL_INT_2_r12 1208 +#define _LOAD_SMALL_INT_2_r23 1209 +#define _LOAD_SMALL_INT_3_r01 1210 +#define _LOAD_SMALL_INT_3_r12 1211 +#define _LOAD_SMALL_INT_3_r23 1212 +#define _LOAD_SPECIAL_r00 1213 +#define _LOAD_SUPER_ATTR_ATTR_r31 1214 +#define _LOAD_SUPER_ATTR_METHOD_r32 1215 +#define _MAKE_CALLARGS_A_TUPLE_r33 1216 +#define _MAKE_CELL_r00 1217 +#define _MAKE_FUNCTION_r11 1218 +#define _MAKE_WARM_r00 1219 +#define _MAKE_WARM_r11 1220 +#define _MAKE_WARM_r22 1221 +#define _MAKE_WARM_r33 1222 +#define _MAP_ADD_r20 1223 +#define _MATCH_CLASS_r31 1224 +#define _MATCH_KEYS_r23 1225 +#define _MATCH_MAPPING_r02 1226 +#define _MATCH_MAPPING_r12 1227 +#define _MATCH_MAPPING_r23 1228 +#define _MATCH_SEQUENCE_r02 1229 +#define _MATCH_SEQUENCE_r12 1230 +#define _MATCH_SEQUENCE_r23 1231 +#define _MAYBE_EXPAND_METHOD_r00 1232 +#define _MAYBE_EXPAND_METHOD_KW_r11 1233 +#define _MONITOR_CALL_r00 1234 +#define _MONITOR_CALL_KW_r11 1235 +#define _MONITOR_JUMP_BACKWARD_r00 1236 +#define _MONITOR_JUMP_BACKWARD_r11 1237 +#define _MONITOR_JUMP_BACKWARD_r22 1238 +#define _MONITOR_JUMP_BACKWARD_r33 1239 +#define _MONITOR_RESUME_r00 1240 +#define _NOP_r00 1241 +#define _NOP_r11 1242 +#define _NOP_r22 1243 +#define _NOP_r33 1244 +#define _POP_CALL_r20 1245 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1246 +#define _POP_CALL_ONE_r30 1247 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1248 +#define _POP_CALL_TWO_r30 1249 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1250 +#define _POP_EXCEPT_r10 1251 +#define _POP_ITER_r20 1252 +#define _POP_JUMP_IF_FALSE_r00 1253 +#define _POP_JUMP_IF_FALSE_r10 1254 +#define _POP_JUMP_IF_FALSE_r21 1255 +#define _POP_JUMP_IF_FALSE_r32 1256 +#define _POP_JUMP_IF_TRUE_r00 1257 +#define _POP_JUMP_IF_TRUE_r10 1258 +#define _POP_JUMP_IF_TRUE_r21 1259 +#define _POP_JUMP_IF_TRUE_r32 1260 +#define _POP_TOP_r10 1261 +#define _POP_TOP_FLOAT_r00 1262 +#define _POP_TOP_FLOAT_r10 1263 +#define _POP_TOP_FLOAT_r21 1264 +#define _POP_TOP_FLOAT_r32 1265 +#define _POP_TOP_INT_r00 1266 +#define _POP_TOP_INT_r10 1267 +#define _POP_TOP_INT_r21 1268 +#define _POP_TOP_INT_r32 1269 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1270 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1271 +#define _POP_TOP_NOP_r00 1272 +#define _POP_TOP_NOP_r10 1273 +#define _POP_TOP_NOP_r21 1274 +#define _POP_TOP_NOP_r32 1275 +#define _POP_TOP_UNICODE_r00 1276 +#define _POP_TOP_UNICODE_r10 1277 +#define _POP_TOP_UNICODE_r21 1278 +#define _POP_TOP_UNICODE_r32 1279 +#define _POP_TWO_r20 1280 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1281 +#define _PUSH_EXC_INFO_r02 1282 +#define _PUSH_EXC_INFO_r12 1283 +#define _PUSH_EXC_INFO_r23 1284 +#define _PUSH_FRAME_r10 1285 +#define _PUSH_NULL_r01 1286 +#define _PUSH_NULL_r12 1287 +#define _PUSH_NULL_r23 1288 +#define _PUSH_NULL_CONDITIONAL_r00 1289 +#define _PY_FRAME_EX_r31 1290 +#define _PY_FRAME_GENERAL_r01 1291 +#define _PY_FRAME_KW_r11 1292 +#define _QUICKEN_RESUME_r00 1293 +#define _QUICKEN_RESUME_r11 1294 +#define _QUICKEN_RESUME_r22 1295 +#define _QUICKEN_RESUME_r33 1296 +#define _REPLACE_WITH_TRUE_r02 1297 +#define _REPLACE_WITH_TRUE_r12 1298 +#define _REPLACE_WITH_TRUE_r23 1299 +#define _RESUME_CHECK_r00 1300 +#define _RESUME_CHECK_r11 1301 +#define _RESUME_CHECK_r22 1302 +#define _RESUME_CHECK_r33 1303 +#define _RETURN_GENERATOR_r01 1304 +#define _RETURN_VALUE_r11 1305 +#define _SAVE_RETURN_OFFSET_r00 1306 +#define _SAVE_RETURN_OFFSET_r11 1307 +#define _SAVE_RETURN_OFFSET_r22 1308 +#define _SAVE_RETURN_OFFSET_r33 1309 +#define _SEND_r22 1310 +#define _SEND_GEN_FRAME_r22 1311 +#define _SETUP_ANNOTATIONS_r00 1312 +#define _SET_ADD_r10 1313 +#define _SET_FUNCTION_ATTRIBUTE_r01 1314 +#define _SET_FUNCTION_ATTRIBUTE_r11 1315 +#define _SET_FUNCTION_ATTRIBUTE_r21 1316 +#define _SET_FUNCTION_ATTRIBUTE_r32 1317 +#define _SET_IP_r00 1318 +#define _SET_IP_r11 1319 +#define _SET_IP_r22 1320 +#define _SET_IP_r33 1321 +#define _SET_UPDATE_r10 1322 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1323 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1324 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1325 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1326 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1327 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1328 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1329 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1330 +#define _SPILL_OR_RELOAD_r01 1331 +#define _SPILL_OR_RELOAD_r02 1332 +#define _SPILL_OR_RELOAD_r03 1333 +#define _SPILL_OR_RELOAD_r10 1334 +#define _SPILL_OR_RELOAD_r12 1335 +#define _SPILL_OR_RELOAD_r13 1336 +#define _SPILL_OR_RELOAD_r20 1337 +#define _SPILL_OR_RELOAD_r21 1338 +#define _SPILL_OR_RELOAD_r23 1339 +#define _SPILL_OR_RELOAD_r30 1340 +#define _SPILL_OR_RELOAD_r31 1341 +#define _SPILL_OR_RELOAD_r32 1342 +#define _START_EXECUTOR_r00 1343 +#define _STORE_ATTR_r20 1344 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1345 +#define _STORE_ATTR_SLOT_r21 1346 +#define _STORE_ATTR_WITH_HINT_r21 1347 +#define _STORE_DEREF_r10 1348 +#define _STORE_FAST_LOAD_FAST_r11 1349 +#define _STORE_FAST_STORE_FAST_r20 1350 +#define _STORE_GLOBAL_r10 1351 +#define _STORE_NAME_r10 1352 +#define _STORE_SLICE_r30 1353 +#define _STORE_SUBSCR_r30 1354 +#define _STORE_SUBSCR_DICT_r31 1355 +#define _STORE_SUBSCR_LIST_INT_r32 1356 +#define _SWAP_r11 1357 +#define _SWAP_2_r02 1358 +#define _SWAP_2_r12 1359 +#define _SWAP_2_r22 1360 +#define _SWAP_2_r33 1361 +#define _SWAP_3_r03 1362 +#define _SWAP_3_r13 1363 +#define _SWAP_3_r23 1364 +#define _SWAP_3_r33 1365 +#define _SWAP_FAST_r01 1366 +#define _SWAP_FAST_r11 1367 +#define _SWAP_FAST_r22 1368 +#define _SWAP_FAST_r33 1369 +#define _SWAP_FAST_0_r01 1370 +#define _SWAP_FAST_0_r11 1371 +#define _SWAP_FAST_0_r22 1372 +#define _SWAP_FAST_0_r33 1373 +#define _SWAP_FAST_1_r01 1374 +#define _SWAP_FAST_1_r11 1375 +#define _SWAP_FAST_1_r22 1376 +#define _SWAP_FAST_1_r33 1377 +#define _SWAP_FAST_2_r01 1378 +#define _SWAP_FAST_2_r11 1379 +#define _SWAP_FAST_2_r22 1380 +#define _SWAP_FAST_2_r33 1381 +#define _SWAP_FAST_3_r01 1382 +#define _SWAP_FAST_3_r11 1383 +#define _SWAP_FAST_3_r22 1384 +#define _SWAP_FAST_3_r33 1385 +#define _SWAP_FAST_4_r01 1386 +#define _SWAP_FAST_4_r11 1387 +#define _SWAP_FAST_4_r22 1388 +#define _SWAP_FAST_4_r33 1389 +#define _SWAP_FAST_5_r01 1390 +#define _SWAP_FAST_5_r11 1391 +#define _SWAP_FAST_5_r22 1392 +#define _SWAP_FAST_5_r33 1393 +#define _SWAP_FAST_6_r01 1394 +#define _SWAP_FAST_6_r11 1395 +#define _SWAP_FAST_6_r22 1396 +#define _SWAP_FAST_6_r33 1397 +#define _SWAP_FAST_7_r01 1398 +#define _SWAP_FAST_7_r11 1399 +#define _SWAP_FAST_7_r22 1400 +#define _SWAP_FAST_7_r33 1401 +#define _TIER2_RESUME_CHECK_r00 1402 +#define _TIER2_RESUME_CHECK_r11 1403 +#define _TIER2_RESUME_CHECK_r22 1404 +#define _TIER2_RESUME_CHECK_r33 1405 +#define _TO_BOOL_r11 1406 +#define _TO_BOOL_BOOL_r01 1407 +#define _TO_BOOL_BOOL_r11 1408 +#define _TO_BOOL_BOOL_r22 1409 +#define _TO_BOOL_BOOL_r33 1410 +#define _TO_BOOL_INT_r02 1411 +#define _TO_BOOL_INT_r12 1412 +#define _TO_BOOL_INT_r23 1413 +#define _TO_BOOL_LIST_r02 1414 +#define _TO_BOOL_LIST_r12 1415 +#define _TO_BOOL_LIST_r23 1416 +#define _TO_BOOL_NONE_r01 1417 +#define _TO_BOOL_NONE_r11 1418 +#define _TO_BOOL_NONE_r22 1419 +#define _TO_BOOL_NONE_r33 1420 +#define _TO_BOOL_STR_r02 1421 +#define _TO_BOOL_STR_r12 1422 +#define _TO_BOOL_STR_r23 1423 +#define _TRACE_RECORD_r00 1424 +#define _UNARY_INVERT_r12 1425 +#define _UNARY_NEGATIVE_r12 1426 +#define _UNARY_NOT_r01 1427 +#define _UNARY_NOT_r11 1428 +#define _UNARY_NOT_r22 1429 +#define _UNARY_NOT_r33 1430 +#define _UNPACK_EX_r10 1431 +#define _UNPACK_SEQUENCE_r10 1432 +#define _UNPACK_SEQUENCE_LIST_r10 1433 +#define _UNPACK_SEQUENCE_TUPLE_r10 1434 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1435 +#define _WITH_EXCEPT_START_r33 1436 +#define _YIELD_VALUE_r11 1437 +#define MAX_UOP_REGS_ID 1437 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index d19f219c165..07c4f0aeb4a 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -201,10 +201,8 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_LOAD_ATTR_PROPERTY_FRAME] = HAS_ARG_FLAG | HAS_DEOPT_FLAG, [_GUARD_DORV_NO_DICT] = HAS_EXIT_FLAG, [_STORE_ATTR_INSTANCE_VALUE] = HAS_ESCAPES_FLAG, - [_STORE_ATTR_INSTANCE_VALUE_NULL] = HAS_DEOPT_FLAG, [_STORE_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, [_STORE_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG, - [_STORE_ATTR_SLOT_NULL] = HAS_DEOPT_FLAG, [_COMPARE_OP] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_COMPARE_OP_FLOAT] = HAS_ARG_FLAG, [_COMPARE_OP_INT] = HAS_ARG_FLAG, @@ -1885,15 +1883,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, - [_STORE_ATTR_INSTANCE_VALUE_NULL] = { - .best = { 0, 1, 2, 3 }, - .entries = { - { 1, 0, _STORE_ATTR_INSTANCE_VALUE_NULL_r01 }, - { 1, 1, _STORE_ATTR_INSTANCE_VALUE_NULL_r11 }, - { 1, 2, _STORE_ATTR_INSTANCE_VALUE_NULL_r21 }, - { 2, 3, _STORE_ATTR_INSTANCE_VALUE_NULL_r32 }, - }, - }, [_STORE_ATTR_WITH_HINT] = { .best = { 2, 2, 2, 2 }, .entries = { @@ -1912,15 +1901,6 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, - [_STORE_ATTR_SLOT_NULL] = { - .best = { 0, 1, 2, 3 }, - .entries = { - { 1, 0, _STORE_ATTR_SLOT_NULL_r01 }, - { 1, 1, _STORE_ATTR_SLOT_NULL_r11 }, - { 1, 2, _STORE_ATTR_SLOT_NULL_r21 }, - { 2, 3, _STORE_ATTR_SLOT_NULL_r32 }, - }, - }, [_COMPARE_OP] = { .best = { 2, 2, 2, 2 }, .entries = { @@ -3835,16 +3815,8 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_GUARD_DORV_NO_DICT_r22] = _GUARD_DORV_NO_DICT, [_GUARD_DORV_NO_DICT_r33] = _GUARD_DORV_NO_DICT, [_STORE_ATTR_INSTANCE_VALUE_r21] = _STORE_ATTR_INSTANCE_VALUE, - [_STORE_ATTR_INSTANCE_VALUE_NULL_r01] = _STORE_ATTR_INSTANCE_VALUE_NULL, - [_STORE_ATTR_INSTANCE_VALUE_NULL_r11] = _STORE_ATTR_INSTANCE_VALUE_NULL, - [_STORE_ATTR_INSTANCE_VALUE_NULL_r21] = _STORE_ATTR_INSTANCE_VALUE_NULL, - [_STORE_ATTR_INSTANCE_VALUE_NULL_r32] = _STORE_ATTR_INSTANCE_VALUE_NULL, [_STORE_ATTR_WITH_HINT_r21] = _STORE_ATTR_WITH_HINT, [_STORE_ATTR_SLOT_r21] = _STORE_ATTR_SLOT, - [_STORE_ATTR_SLOT_NULL_r01] = _STORE_ATTR_SLOT_NULL, - [_STORE_ATTR_SLOT_NULL_r11] = _STORE_ATTR_SLOT_NULL, - [_STORE_ATTR_SLOT_NULL_r21] = _STORE_ATTR_SLOT_NULL, - [_STORE_ATTR_SLOT_NULL_r32] = _STORE_ATTR_SLOT_NULL, [_COMPARE_OP_r21] = _COMPARE_OP, [_COMPARE_OP_FLOAT_r03] = _COMPARE_OP_FLOAT, [_COMPARE_OP_FLOAT_r13] = _COMPARE_OP_FLOAT, @@ -5262,18 +5234,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_STORE_ATTR_r20] = "_STORE_ATTR_r20", [_STORE_ATTR_INSTANCE_VALUE] = "_STORE_ATTR_INSTANCE_VALUE", [_STORE_ATTR_INSTANCE_VALUE_r21] = "_STORE_ATTR_INSTANCE_VALUE_r21", - [_STORE_ATTR_INSTANCE_VALUE_NULL] = "_STORE_ATTR_INSTANCE_VALUE_NULL", - [_STORE_ATTR_INSTANCE_VALUE_NULL_r01] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r01", - [_STORE_ATTR_INSTANCE_VALUE_NULL_r11] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r11", - [_STORE_ATTR_INSTANCE_VALUE_NULL_r21] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r21", - [_STORE_ATTR_INSTANCE_VALUE_NULL_r32] = "_STORE_ATTR_INSTANCE_VALUE_NULL_r32", [_STORE_ATTR_SLOT] = "_STORE_ATTR_SLOT", [_STORE_ATTR_SLOT_r21] = "_STORE_ATTR_SLOT_r21", - [_STORE_ATTR_SLOT_NULL] = "_STORE_ATTR_SLOT_NULL", - [_STORE_ATTR_SLOT_NULL_r01] = "_STORE_ATTR_SLOT_NULL_r01", - [_STORE_ATTR_SLOT_NULL_r11] = "_STORE_ATTR_SLOT_NULL_r11", - [_STORE_ATTR_SLOT_NULL_r21] = "_STORE_ATTR_SLOT_NULL_r21", - [_STORE_ATTR_SLOT_NULL_r32] = "_STORE_ATTR_SLOT_NULL_r32", [_STORE_ATTR_WITH_HINT] = "_STORE_ATTR_WITH_HINT", [_STORE_ATTR_WITH_HINT_r21] = "_STORE_ATTR_WITH_HINT_r21", [_STORE_DEREF] = "_STORE_DEREF", @@ -5735,14 +5697,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _STORE_ATTR_INSTANCE_VALUE: return 2; - case _STORE_ATTR_INSTANCE_VALUE_NULL: - return 2; case _STORE_ATTR_WITH_HINT: return 2; case _STORE_ATTR_SLOT: return 2; - case _STORE_ATTR_SLOT_NULL: - return 2; case _COMPARE_OP: return 2; case _COMPARE_OP_FLOAT: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst deleted file mode 100644 index 561cda68706..00000000000 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-30-09-47-29.gh-issue-144145.mxJyUj.rst +++ /dev/null @@ -1 +0,0 @@ -Track nullness of attributes of objects in the JIT optimizer. Patch by Hai Zhu. diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8bc58240e90..4c808016a00 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -2671,23 +2671,6 @@ dummy_func( Py_XDECREF(old_value); } - op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - - STAT_INC(STORE_ATTR, hit); - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; - DEOPT_IF(old_value != NULL); - FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - UNLOCK_OBJECT(owner_o); - INPUTS_DEAD(); - o = owner; - } - macro(STORE_ATTR_INSTANCE_VALUE) = unused/1 + _GUARD_TYPE_VERSION_AND_LOCK + @@ -2750,20 +2733,6 @@ dummy_func( Py_XDECREF(old_value); } - op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) { - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - - DEOPT_IF(!LOCK_OBJECT(owner_o)); - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - DEOPT_IF(old_value != NULL); - FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); - UNLOCK_OBJECT(owner_o); - INPUTS_DEAD(); - o = owner; - } - macro(STORE_ATTR_SLOT) = unused/1 + _GUARD_TYPE_VERSION + diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1a705098472..8901c259525 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -9782,147 +9782,6 @@ break; } - case _STORE_ATTR_INSTANCE_VALUE_NULL_r01: { - CHECK_CURRENT_CACHED_VALUES(0); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - STAT_INC(STORE_ATTR, hit); - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_INSTANCE_VALUE_NULL_r11: { - CHECK_CURRENT_CACHED_VALUES(1); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - owner = _stack_item_0; - value = stack_pointer[-1]; - uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - STAT_INC(STORE_ATTR, hit); - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_INSTANCE_VALUE_NULL_r21: { - CHECK_CURRENT_CACHED_VALUES(2); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - owner = _stack_item_1; - value = _stack_item_0; - uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - STAT_INC(STORE_ATTR, hit); - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = owner; - _tos_cache0 = value; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_INSTANCE_VALUE_NULL_r32: { - CHECK_CURRENT_CACHED_VALUES(3); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - _PyStackRef _stack_item_2 = _tos_cache2; - owner = _stack_item_2; - value = _stack_item_1; - uint16_t offset = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - STAT_INC(STORE_ATTR, hit); - assert(_PyObject_GetManagedDict(owner_o) == NULL); - PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset); - PyObject *old_value = *value_ptr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = owner; - _tos_cache1 = value; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value)); - PyDictValues *values = _PyObject_InlineValues(owner_o); - Py_ssize_t index = value_ptr - values->values; - _PyDictValues_AddToInsertionOrder(values, index); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache1 = o; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - case _STORE_ATTR_WITH_HINT_r21: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); @@ -10055,157 +9914,6 @@ break; } - case _STORE_ATTR_SLOT_NULL_r01: { - CHECK_CURRENT_CACHED_VALUES(0); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - if (!LOCK_OBJECT(owner_o)) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_SLOT_NULL_r11: { - CHECK_CURRENT_CACHED_VALUES(1); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - owner = _stack_item_0; - value = stack_pointer[-1]; - uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - if (!LOCK_OBJECT(owner_o)) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = owner; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_SLOT_NULL_r21: { - CHECK_CURRENT_CACHED_VALUES(2); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - owner = _stack_item_1; - value = _stack_item_0; - uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - if (!LOCK_OBJECT(owner_o)) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = owner; - _tos_cache0 = value; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = owner; - _tos_cache0 = value; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache0 = o; - SET_CURRENT_CACHED_VALUES(1); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - - case _STORE_ATTR_SLOT_NULL_r32: { - CHECK_CURRENT_CACHED_VALUES(3); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - _PyStackRef owner; - _PyStackRef value; - _PyStackRef o; - _PyStackRef _stack_item_0 = _tos_cache0; - _PyStackRef _stack_item_1 = _tos_cache1; - _PyStackRef _stack_item_2 = _tos_cache2; - owner = _stack_item_2; - value = _stack_item_1; - uint16_t index = (uint16_t)CURRENT_OPERAND0_16(); - PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); - if (!LOCK_OBJECT(owner_o)) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = owner; - _tos_cache1 = value; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } - char *addr = (char *)owner_o + index; - STAT_INC(STORE_ATTR, hit); - PyObject *old_value = *(PyObject **)addr; - if (old_value != NULL) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = owner; - _tos_cache1 = value; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } - FT_ATOMIC_STORE_PTR_RELEASE(*(PyObject **)addr, PyStackRef_AsPyObjectSteal(value)); - UNLOCK_OBJECT(owner_o); - o = owner; - _tos_cache1 = o; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - break; - } - case _COMPARE_OP_r21: { CHECK_CURRENT_CACHED_VALUES(2); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 0a1f2672f4b..039aacf23ae 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -269,9 +269,6 @@ add_op(JitOptContext *ctx, _PyUOpInstruction *this_instr, #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness -#define sym_new_descr_object _Py_uop_sym_new_descr_object -#define sym_get_attr _Py_uop_sym_get_attr -#define sym_set_attr _Py_uop_sym_set_attr #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing @@ -506,6 +503,7 @@ optimize_uops( int oparg = this_instr->oparg; opcode = this_instr->opcode; + if (!CURRENT_FRAME_IS_INIT_SHIM()) { stack_pointer = ctx->frame->stack_pointer; } @@ -526,15 +524,9 @@ optimize_uops( if (ctx->out_buffer.next == out_ptr) { *(ctx->out_buffer.next++) = *this_instr; } - // Track escapes - but skip when from init shim frame, since self hasn't escaped yet - bool is_init_shim = CURRENT_FRAME_IS_INIT_SHIM(); - if ((_PyUop_Flags[out_ptr->opcode] & HAS_ESCAPES_FLAG) && !is_init_shim) - { - ctx->last_escape_index = uop_buffer_length(&ctx->out_buffer) - 1; - } assert(ctx->frame != NULL); DUMP_UOP(ctx, "out", uop_buffer_length(&ctx->out_buffer) - 1, out_ptr, stack_pointer); - if (!is_init_shim && !ctx->done) { + if (!CURRENT_FRAME_IS_INIT_SHIM() && !ctx->done) { DPRINTF(3, " stack_level %d\n", STACK_LEVEL()); ctx->frame->stack_pointer = stack_pointer; assert(STACK_LEVEL() >= 0); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 4ccecd472b3..5a3480ab316 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -38,9 +38,6 @@ typedef struct _Py_UOpsAbstractFrame _Py_UOpsAbstractFrame; #define sym_new_compact_int _Py_uop_sym_new_compact_int #define sym_is_compact_int _Py_uop_sym_is_compact_int #define sym_new_truthiness _Py_uop_sym_new_truthiness -#define sym_new_descr_object _Py_uop_sym_new_descr_object -#define sym_get_attr _Py_uop_sym_get_attr -#define sym_set_attr _Py_uop_sym_set_attr #define sym_new_predicate _Py_uop_sym_new_predicate #define sym_apply_predicate_narrowing _Py_uop_sym_apply_predicate_narrowing @@ -106,14 +103,6 @@ dummy_func(void) { } op(_STORE_ATTR_INSTANCE_VALUE, (offset/1, value, owner -- o)) { - JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value); - if (sym_is_null(old_value)) { - ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset); - } - o = owner; - } - - op(_STORE_ATTR_INSTANCE_VALUE_NULL, (offset/1, value, owner -- o)) { (void)value; o = owner; } @@ -136,14 +125,7 @@ dummy_func(void) { } op(_STORE_ATTR_SLOT, (index/1, value, owner -- o)) { - JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value); - if (sym_is_null(old_value)) { - ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index); - } - o = owner; - } - - op(_STORE_ATTR_SLOT_NULL, (index/1, value, owner -- o)) { + (void)index; (void)value; o = owner; } @@ -767,7 +749,8 @@ dummy_func(void) { } op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, o)) { - attr = sym_get_attr(ctx, owner, (uint16_t)index); + attr = sym_new_not_null(ctx); + (void)index; o = owner; } @@ -951,14 +934,10 @@ dummy_func(void) { } op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { + (void)type_version; (void)args; callable = sym_new_not_null(ctx); - PyTypeObject *tp = _PyType_LookupByVersion(type_version); - if (tp != NULL) { - self_or_null = sym_new_descr_object(ctx, type_version); - } else { - self_or_null = sym_new_not_null(ctx); - } + self_or_null = sym_new_not_null(ctx); } op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 4a6f2450680..9dc1da3c93b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1936,7 +1936,8 @@ JitOptRef o; owner = stack_pointer[-1]; uint16_t index = (uint16_t)this_instr->operand0; - attr = sym_get_attr(ctx, owner, (uint16_t)index); + attr = sym_new_not_null(ctx); + (void)index; o = owner; CHECK_STACK_BOUNDS(1); stack_pointer[-1] = attr; @@ -2005,25 +2006,6 @@ } case _STORE_ATTR_INSTANCE_VALUE: { - JitOptRef owner; - JitOptRef value; - JitOptRef o; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t offset = (uint16_t)this_instr->operand0; - JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)offset, value); - if (sym_is_null(old_value)) { - ADD_OP(_STORE_ATTR_INSTANCE_VALUE_NULL, 0, offset); - } - o = owner; - CHECK_STACK_BOUNDS(-1); - stack_pointer[-2] = o; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - break; - } - - case _STORE_ATTR_INSTANCE_VALUE_NULL: { JitOptRef owner; JitOptRef value; JitOptRef o; @@ -2062,25 +2044,7 @@ owner = stack_pointer[-1]; value = stack_pointer[-2]; uint16_t index = (uint16_t)this_instr->operand0; - JitOptRef old_value = sym_set_attr(ctx, owner, (uint16_t)index, value); - if (sym_is_null(old_value)) { - ADD_OP(_STORE_ATTR_SLOT_NULL, 0, index); - } - o = owner; - CHECK_STACK_BOUNDS(-1); - stack_pointer[-2] = o; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - break; - } - - case _STORE_ATTR_SLOT_NULL: { - JitOptRef owner; - JitOptRef value; - JitOptRef o; - owner = stack_pointer[-1]; - value = stack_pointer[-2]; - uint16_t index = (uint16_t)this_instr->operand0; + (void)index; (void)value; o = owner; CHECK_STACK_BOUNDS(-1); @@ -3228,15 +3192,11 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t type_version = (uint32_t)this_instr->operand0; + (void)type_version; (void)args; callable = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); stack_pointer[-2 - oparg] = callable; - PyTypeObject *tp = _PyType_LookupByVersion(type_version); - if (tp != NULL) { - self_or_null = sym_new_descr_object(ctx, type_version); - } else { - self_or_null = sym_new_not_null(ctx); - } stack_pointer[-1 - oparg] = self_or_null; break; } diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index d79c273a099..bdf1b860d4e 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -116,15 +116,6 @@ _PyUOpSymPrint(JitOptRef ref) case JIT_SYM_PREDICATE_TAG: printf("", (void *)sym); break; - case JIT_SYM_DESCR_TAG: { - PyTypeObject *descr_type = _PyType_LookupByVersion(sym->descr.type_version); - if (descr_type) { - printf("<%s descr[%d] v%u at %p>", descr_type->tp_name, sym->descr.num_descrs, sym->descr.type_version, (void *)sym); - } else { - printf("", sym->descr.num_descrs, sym->descr.type_version, (void *)sym); - } - break; - } default: printf("", sym->tag, (void *)sym); break; @@ -332,11 +323,6 @@ _Py_uop_sym_set_type(JitOptContext *ctx, JitOptRef ref, PyTypeObject *typ) sym_set_bottom(ctx, sym); } return; - case JIT_SYM_DESCR_TAG: - if (typ->tp_version_tag != sym->descr.type_version) { - sym_set_bottom(ctx, sym); - } - return; } } @@ -401,12 +387,6 @@ _Py_uop_sym_set_type_version(JitOptContext *ctx, JitOptRef ref, unsigned int ver return false; } return true; - case JIT_SYM_DESCR_TAG: - if (version != sym->descr.type_version) { - sym_set_bottom(ctx, sym); - return false; - } - return true; } Py_UNREACHABLE(); } @@ -506,9 +486,6 @@ _Py_uop_sym_set_const(JitOptContext *ctx, JitOptRef ref, PyObject *const_val) sym_set_bottom(ctx, sym); } return; - case JIT_SYM_DESCR_TAG: - sym_set_bottom(ctx, sym); - return; } } @@ -629,8 +606,7 @@ _Py_uop_sym_get_type(JitOptRef ref) return &PyBool_Type; case JIT_SYM_COMPACT_INT: return &PyLong_Type; - case JIT_SYM_DESCR_TAG: - return _PyType_LookupByVersion(sym->descr.type_version); + } Py_UNREACHABLE(); } @@ -659,8 +635,6 @@ _Py_uop_sym_get_type_version(JitOptRef ref) return PyBool_Type.tp_version_tag; case JIT_SYM_COMPACT_INT: return PyLong_Type.tp_version_tag; - case JIT_SYM_DESCR_TAG: - return sym->descr.type_version; } Py_UNREACHABLE(); } @@ -696,7 +670,6 @@ _Py_uop_sym_truthiness(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_UNKNOWN_TAG: case JIT_SYM_COMPACT_INT: case JIT_SYM_PREDICATE_TAG: - case JIT_SYM_DESCR_TAG: return -1; case JIT_SYM_KNOWN_CLASS_TAG: /* TODO : @@ -854,7 +827,6 @@ _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef ref) case JIT_SYM_TUPLE_TAG: case JIT_SYM_PREDICATE_TAG: case JIT_SYM_TRUTHINESS_TAG: - case JIT_SYM_DESCR_TAG: sym_set_bottom(ctx, sym); return; case JIT_SYM_BOTTOM_TAG: @@ -969,116 +941,6 @@ _Py_uop_sym_new_compact_int(JitOptContext *ctx) return PyJitRef_Wrap(sym); } -JitOptRef -_Py_uop_sym_new_descr_object(JitOptContext *ctx, unsigned int type_version) -{ - JitOptSymbol *res = sym_new(ctx); - if (res == NULL) { - return out_of_space_ref(ctx); - } - res->tag = JIT_SYM_DESCR_TAG; - res->descr.num_descrs = 0; - res->descr.descrs = NULL; - res->descr.type_version = type_version; - res->descr.last_modified_index = uop_buffer_length(&ctx->out_buffer); - return PyJitRef_Wrap(res); -} - -JitOptRef -_Py_uop_sym_get_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index) -{ - JitOptSymbol *sym = PyJitRef_Unwrap(ref); - - switch (sym->tag) { - case JIT_SYM_DESCR_TAG: - // Only return tracked slot values if: - // 1. Symbol has mappings allocated - // 2. No escape has occurred since last modification (state is fresh) - if (sym->descr.descrs != NULL && - sym->descr.last_modified_index >= ctx->last_escape_index) - { - for (int i = 0; i < sym->descr.num_descrs; i++) { - if (sym->descr.descrs[i].slot_index == slot_index) { - return PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol); - } - } - } - break; - default: - break; - } - - return _Py_uop_sym_new_not_null(ctx); -} - -static JitOptDescrMapping * -descr_arena_alloc(JitOptContext *ctx) -{ - if (ctx->d_arena.descr_curr_number + MAX_SYMBOLIC_DESCR_SIZE > ctx->d_arena.descr_max_number) { - return NULL; - } - JitOptDescrMapping *descrs = &ctx->d_arena.arena[ctx->d_arena.descr_curr_number]; - ctx->d_arena.descr_curr_number += MAX_SYMBOLIC_DESCR_SIZE; - return descrs; -} - -JitOptRef -_Py_uop_sym_set_attr(JitOptContext *ctx, JitOptRef ref, uint16_t slot_index, JitOptRef value) -{ - JitOptSymbol *sym = PyJitRef_Unwrap(ref); - int curr_index = uop_buffer_length(&ctx->out_buffer); - - switch (sym->tag) { - case JIT_SYM_DESCR_TAG: - break; - default: - return _Py_uop_sym_new_not_null(ctx); - } - - // Check escape - if (sym->descr.last_modified_index < ctx->last_escape_index) { - sym->descr.num_descrs = 0; - } - - // Get old value before updating - JitOptRef old_value = PyJitRef_NULL; - if (sym->descr.descrs != NULL) { - for (int i = 0; i < sym->descr.num_descrs; i++) { - if (sym->descr.descrs[i].slot_index == slot_index) { - old_value = PyJitRef_Wrap(allocation_base(ctx) + sym->descr.descrs[i].symbol); - break; - } - } - } - - // Update the last modified timestamp - sym->descr.last_modified_index = curr_index; - - // Check if have arena space allocated - if (sym->descr.descrs == NULL) { - sym->descr.descrs = descr_arena_alloc(ctx); - if (sym->descr.descrs == NULL) { - return PyJitRef_IsNull(old_value) ? _Py_uop_sym_new_not_null(ctx) : old_value; - } - } - // Check if the slot already exists - for (int i = 0; i < sym->descr.num_descrs; i++) { - if (sym->descr.descrs[i].slot_index == slot_index) { - sym->descr.descrs[i].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx)); - assert(!PyJitRef_IsNull(old_value)); - return old_value; - } - } - // Add new mapping if there's space - if (sym->descr.num_descrs < MAX_SYMBOLIC_DESCR_SIZE) { - int idx = sym->descr.num_descrs++; - sym->descr.descrs[idx].slot_index = slot_index; - sym->descr.descrs[idx].symbol = (uint16_t)(PyJitRef_Unwrap(value) - allocation_base(ctx)); - } - - return PyJitRef_IsNull(old_value) ? PyJitRef_Borrow(_Py_uop_sym_new_null(ctx)) : old_value; -} - // 0 on success, -1 on error. _Py_UOpsAbstractFrame * _Py_uop_frame_new( @@ -1168,10 +1030,6 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx) ctx->t_arena.ty_curr_number = 0; ctx->t_arena.ty_max_number = TY_ARENA_SIZE; - // Setup the arena for descriptor mappings. - ctx->d_arena.descr_curr_number = 0; - ctx->d_arena.descr_max_number = DESCR_ARENA_SIZE; - // Frame setup ctx->curr_frame_depth = 0; @@ -1182,7 +1040,6 @@ _Py_uop_abstractcontext_init(JitOptContext *ctx) ctx->out_of_space = false; ctx->contradiction = false; ctx->builtins_watched = false; - ctx->last_escape_index = 0; } int @@ -1664,61 +1521,6 @@ _Py_uop_symbols_test(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored)) TEST_PREDICATE(_Py_uop_sym_matches_type(ref_int, &PyLong_Type), "43 is not an int"); TEST_PREDICATE(_Py_uop_sym_get_const(ctx, ref_int) == val_43, "43 isn't 43"); - JitOptRef descr_obj = _Py_uop_sym_new_descr_object(ctx, 42); - TEST_PREDICATE(!_Py_uop_sym_is_null(descr_obj), "descr object is NULL"); - TEST_PREDICATE(_Py_uop_sym_is_not_null(descr_obj), "descr object is not not-null"); - TEST_PREDICATE(_Py_uop_sym_get_type_version(descr_obj) == 42, - "descr object has wrong type version"); - - JitOptRef slot_val = _Py_uop_sym_new_const(ctx, val_42); - JitOptRef old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val); - TEST_PREDICATE(_Py_uop_sym_is_null(old_val), "set_attr on new slot should return NULL"); - JitOptRef retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, - "descr getattr(0) didn't return val_42"); - - JitOptRef missing = _Py_uop_sym_get_attr(ctx, descr_obj, 99); - TEST_PREDICATE(_Py_uop_sym_is_not_null(missing), "missing slot is not not-null"); - TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, missing), "missing slot is const"); - - JitOptRef slot_val2 = _Py_uop_sym_new_const(ctx, val_43); - old_val = _Py_uop_sym_set_attr(ctx, descr_obj, 0, slot_val2); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, old_val) == val_42, - "set_attr should return old value (val_42)"); - retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43, - "descr getattr(0) didn't return val_43 after update"); - - // Test multiple slots - JitOptRef slot_val3 = _Py_uop_sym_new_const(ctx, val_42); - _Py_uop_sym_set_attr(ctx, descr_obj, 1, slot_val3); - retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 1); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, - "descr getattr(1) didn't return val_42"); - retrieved = _Py_uop_sym_get_attr(ctx, descr_obj, 0); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_43, - "descr getattr(0) changed unexpectedly"); - - // Test escape invalidation - JitOptRef descr_obj3 = _Py_uop_sym_new_descr_object(ctx, 100); - JitOptRef escape_val = _Py_uop_sym_new_const(ctx, val_42); - _Py_uop_sym_set_attr(ctx, descr_obj3, 0, escape_val); - retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0); - TEST_PREDICATE(_Py_uop_sym_get_const(ctx, retrieved) == val_42, - "descr getattr before escape didn't return val_42"); - // Simulate escape by setting last_escape_index higher - ctx->last_escape_index = INT_MAX; - retrieved = _Py_uop_sym_get_attr(ctx, descr_obj3, 0); - TEST_PREDICATE(!_Py_uop_sym_is_const(ctx, retrieved), - "descr getattr after escape should not return const"); - TEST_PREDICATE(_Py_uop_sym_is_not_null(retrieved), - "descr getattr after escape should return not-null"); - ctx->last_escape_index = 0; - - JitOptRef descr_obj2 = _Py_uop_sym_new_descr_object(ctx, 42); - _Py_uop_sym_set_type_version(ctx, descr_obj2, 43); - TEST_PREDICATE(_Py_uop_sym_is_bottom(descr_obj2), - "descr object with wrong type version isn't bottom"); _Py_uop_abstractcontext_fini(ctx); Py_DECREF(val_42); Py_DECREF(val_43); From afc2aeb85026173d1daf33f323f0070c9e75def2 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 2 Feb 2026 15:32:25 +0100 Subject: [PATCH 126/133] gh-134160: "First extension module" tutorial improvements (GH-144183) - Pass -v to pip, so compiler output is visible - Move the call ``spam.system(3)`` up so that error handling is tested right after it's added - Use `PyUnicode_AsUTF8AndSize` as `PyUnicode_AsUTF8` is not in the Limited API. - Add a footnote about embedded NULs. --- Doc/extending/first-extension-module.rst | 56 ++++++++++++++------- Doc/includes/capi-extension/spammodule-01.c | 2 +- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Doc/extending/first-extension-module.rst b/Doc/extending/first-extension-module.rst index 5bde785c49e..f1ba0a3ceb7 100644 --- a/Doc/extending/first-extension-module.rst +++ b/Doc/extending/first-extension-module.rst @@ -171,7 +171,10 @@ Now, build install the *project in the current directory* (``.``) via ``pip``: .. code-block:: sh - python -m pip install . + python -m pip -v install . + +The ``-v`` (``--verbose``) option causes ``pip`` to show the output from +the compiler, which is often useful during development. .. tip:: @@ -460,7 +463,7 @@ So, we'll need to *encode* the data, and we'll use the UTF-8 encoding for it. 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]_. +:c:func:`PyUnicode_AsUTF8AndSize` [#why-pyunicodeasutf8]_. Call it like this: .. code-block:: c @@ -469,31 +472,31 @@ Call it like this: static PyObject * spam_system(PyObject *self, PyObject *arg) { - const char *command = PyUnicode_AsUTF8(arg); + const char *command = PyUnicode_AsUTF8AndSize(arg, NULL); 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. +If :c:func:`PyUnicode_AsUTF8AndSize` is successful, *command* will point to the +resulting C string -- a zero-terminated array of bytes [#embedded-nul]_. 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 + After ``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`` +If :c:func:`PyUnicode_AsUTF8AndSize` 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``. +For the :c:func:`PyUnicode_AsUTF8AndSize` call, the correct way to handle +errors is returning ``NULL`` from ``spam_system``. Add an ``if`` block for this: @@ -503,7 +506,7 @@ Add an ``if`` block for this: static PyObject * spam_system(PyObject *self, PyObject *arg) { - const char *command = PyUnicode_AsUTF8(arg); + const char *command = PyUnicode_AsUTF8AndSize(arg); if (command == NULL) { return NULL; } @@ -512,7 +515,18 @@ Add an ``if`` block for this: return result; } -That's it for the setup. +To test that error handling works, compile again, restart Python so that +``import spam`` picks up the new version of your module, and try passing +a non-string value to your function: + +.. code-block:: pycon + + >>> import spam + >>> spam.system(3) + Traceback (most recent call last): + ... + TypeError: bad argument type for built-in operation + 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``: @@ -522,7 +536,7 @@ the ``char *`` buffer, and using its result instead of the ``3``: static PyObject * spam_system(PyObject *self, PyObject *arg) { - const char *command = PyUnicode_AsUTF8(arg); + const char *command = PyUnicode_AsUTF8AndSize(arg); if (command == NULL) { return NULL; } @@ -543,7 +557,8 @@ system command: >>> result 0 -You might also want to test error cases: +You can also test with other commands, like ``ls``, ``dir``, or one +that doesn't exist: .. code-block:: pycon @@ -553,11 +568,6 @@ You might also want to test error cases: >>> result 32512 - >>> spam.system(3) - Traceback (most recent call last): - ... - TypeError: bad argument type for built-in operation - The result ========== @@ -665,3 +675,13 @@ on :py:attr:`sys.path`. type. .. [#why-pyunicodeasutf8] Here, ``PyUnicode`` refers to the original name of the Python :py:class:`str` class: ``unicode``. + + The ``AndSize`` part of the name refers to the fact that this function can + also retrieve the size of the buffer, using an output argument. + We don't need this, so we set the second argument to NULL. +.. [#embedded-nul] We're ignoring the fact that Python strings can also + contain NUL bytes, which terminate a C string. + In other words, our function will treat ``spam.system("foo\0bar")`` as + ``spam.system("foo")``. + This possibility can lead to security issues, so the real ``os.system`` + function size checks for this case and raises an error. diff --git a/Doc/includes/capi-extension/spammodule-01.c b/Doc/includes/capi-extension/spammodule-01.c index 86c9840359d..ac96f17f047 100644 --- a/Doc/includes/capi-extension/spammodule-01.c +++ b/Doc/includes/capi-extension/spammodule-01.c @@ -12,7 +12,7 @@ static PyObject * spam_system(PyObject *self, PyObject *arg) { - const char *command = PyUnicode_AsUTF8(arg); + const char *command = PyUnicode_AsUTF8AndSize(arg, NULL); if (command == NULL) { return NULL; } From 39f16a93ef7b39c3fc5a1a5b706512168baee499 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 2 Feb 2026 23:44:08 +0900 Subject: [PATCH 127/133] gh-142555: Fix null pointer dereference in array.__setitem__ via re-entrant __index__ (GH-142713) --- Lib/test/test_array.py | 40 ++++++++++++ ...-12-15-02-02-45.gh-issue-142555.EC9QN_.rst | 3 + Modules/arraymodule.c | 65 ++++++++++++++++++- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-15-02-02-45.gh-issue-142555.EC9QN_.rst diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index b49df029f03..5c919aea24e 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -8,6 +8,7 @@ from test.support import import_helper from test.support import os_helper from test.support import _2G +from test.support import subTests import weakref import pickle import operator @@ -1697,6 +1698,45 @@ def test_gh_128961(self): it.__setstate__(0) self.assertRaises(StopIteration, next, it) + # Tests for NULL pointer dereference in array.__setitem__ + # when the index conversion mutates the array. + # See: https://github.com/python/cpython/issues/142555. + + @subTests("dtype", ["b", "B", "h", "H", "i", "l", "q", "I", "L", "Q"]) + def test_setitem_use_after_clear_with_int_data(self, dtype): + victim = array.array(dtype, list(range(64))) + + class Index: + def __index__(self): + victim.clear() + return 0 + + self.assertRaises(IndexError, victim.__setitem__, 1, Index()) + self.assertEqual(len(victim), 0) + + def test_setitem_use_after_shrink_with_int_data(self): + victim = array.array('b', [1, 2, 3]) + + class Index: + def __index__(self): + victim.pop() + victim.pop() + return 0 + + self.assertRaises(IndexError, victim.__setitem__, 1, Index()) + + @subTests("dtype", ["f", "d"]) + def test_setitem_use_after_clear_with_float_data(self, dtype): + victim = array.array(dtype, [1.0, 2.0, 3.0]) + + class Float: + def __float__(self): + victim.clear() + return 0.0 + + self.assertRaises(IndexError, victim.__setitem__, 1, Float()) + self.assertEqual(len(victim), 0) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2025-12-15-02-02-45.gh-issue-142555.EC9QN_.rst b/Misc/NEWS.d/next/Library/2025-12-15-02-02-45.gh-issue-142555.EC9QN_.rst new file mode 100644 index 00000000000..72cc7c634b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-15-02-02-45.gh-issue-142555.EC9QN_.rst @@ -0,0 +1,3 @@ +:mod:`array`: fix a crash in ``a[i] = v`` when converting *i* to +an index via :meth:`i.__index__ ` or :meth:`i.__float__ +` mutates the array. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 22ec3c31fb3..ec6a9840131 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -205,6 +205,33 @@ Note that the basic Get and Set functions do NOT check that the index is in bounds; that's the responsibility of the caller. ****************************************************************************/ +/* Macro to check array buffer validity and bounds after calling + user-defined methods (like __index__ or __float__) that might modify + the array during the call. +*/ +#define CHECK_ARRAY_BOUNDS(OP, IDX) \ + do { \ + if ((IDX) >= 0 && ((OP)->ob_item == NULL || \ + (IDX) >= Py_SIZE((OP)))) { \ + PyErr_SetString(PyExc_IndexError, \ + "array assignment index out of range"); \ + return -1; \ + } \ + } while (0) + +#define CHECK_ARRAY_BOUNDS_WITH_CLEANUP(OP, IDX, VAL, CLEANUP) \ + do { \ + if ((IDX) >= 0 && ((OP)->ob_item == NULL || \ + (IDX) >= Py_SIZE((OP)))) { \ + PyErr_SetString(PyExc_IndexError, \ + "array assignment index out of range"); \ + if (CLEANUP) { \ + Py_DECREF(VAL); \ + } \ + return -1; \ + } \ + } while (0) + static PyObject * b_getitem(arrayobject *ap, Py_ssize_t i) { @@ -221,7 +248,10 @@ b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) the overflow checking */ if (!PyArg_Parse(v, "h;array item must be integer", &x)) return -1; - else if (x < -128) { + + CHECK_ARRAY_BOUNDS(ap, i); + + if (x < -128) { PyErr_SetString(PyExc_OverflowError, "signed char is less than minimum"); return -1; @@ -250,6 +280,9 @@ BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ if (!PyArg_Parse(v, "b;array item must be integer", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((unsigned char *)ap->ob_item)[i] = x; return 0; @@ -342,6 +375,9 @@ h_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ if (!PyArg_Parse(v, "h;array item must be integer", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((short *)ap->ob_item)[i] = x; return 0; @@ -371,6 +407,9 @@ HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) "unsigned short is greater than maximum"); return -1; } + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((short *)ap->ob_item)[i] = (short)x; return 0; @@ -389,6 +428,9 @@ i_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ if (!PyArg_Parse(v, "i;array item must be integer", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((int *)ap->ob_item)[i] = x; return 0; @@ -432,6 +474,9 @@ II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } + + CHECK_ARRAY_BOUNDS_WITH_CLEANUP(ap, i, v, do_decref); + if (i >= 0) ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; @@ -453,6 +498,9 @@ l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) long x; if (!PyArg_Parse(v, "l;array item must be integer", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((long *)ap->ob_item)[i] = x; return 0; @@ -487,6 +535,9 @@ LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } + + CHECK_ARRAY_BOUNDS_WITH_CLEANUP(ap, i, v, do_decref); + if (i >= 0) ((unsigned long *)ap->ob_item)[i] = x; @@ -508,6 +559,9 @@ q_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) long long x; if (!PyArg_Parse(v, "L;array item must be integer", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((long long *)ap->ob_item)[i] = x; return 0; @@ -543,6 +597,9 @@ QQ_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) } return -1; } + + CHECK_ARRAY_BOUNDS_WITH_CLEANUP(ap, i, v, do_decref); + if (i >= 0) ((unsigned long long *)ap->ob_item)[i] = x; @@ -564,6 +621,9 @@ f_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) float x; if (!PyArg_Parse(v, "f;array item must be float", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((float *)ap->ob_item)[i] = x; return 0; @@ -581,6 +641,9 @@ d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) double x; if (!PyArg_Parse(v, "d;array item must be float", &x)) return -1; + + CHECK_ARRAY_BOUNDS(ap, i); + if (i >= 0) ((double *)ap->ob_item)[i] = x; return 0; From a44782856562025ede013f897d42d0d6e4f085c1 Mon Sep 17 00:00:00 2001 From: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:56:45 +0000 Subject: [PATCH 128/133] gh-144242: Note that issues aren't needed for typos in docs template (GH-144288) --- .github/ISSUE_TEMPLATE/documentation.md | 9 --------- .github/ISSUE_TEMPLATE/documentation.yml | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/documentation.md create mode 100644 .github/ISSUE_TEMPLATE/documentation.yml diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md deleted file mode 100644 index 174fd39171d..00000000000 --- a/.github/ISSUE_TEMPLATE/documentation.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: Documentation -about: Report a problem with the documentation -labels: "docs" ---- - -# Documentation - -(A clear and concise description of the issue.) diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 00000000000..944e590452c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,15 @@ +name: Documentation +description: Report a problem with the documentation +labels: ["docs"] +body: + - type: markdown + attributes: + value: | + > [!NOTE] + > Trivial changes (for example typos) don’t require an issue before opening a PR. + - type: textarea + attributes: + label: "Documentation" + description: "A clear and concise description of the issue." + validations: + required: true From 5f91577cdd09bc604001ccfc164042ddbe486a81 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson Date: Mon, 2 Feb 2026 09:55:11 -0600 Subject: [PATCH 129/133] gh-144376: Only run 'address' fuzzer for python3-libraries (#144398) --- .github/workflows/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e7f7aa5172e..046e678f8c1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -655,11 +655,14 @@ jobs: matrix: sanitizer: - address - - undefined - - memory oss-fuzz-project-name: - cpython3 - python3-libraries + include: + - sanitizer: undefined + oss-fuzz-project-name: cpython3 + - sanitizer: memory + oss-fuzz-project-name: cpython3 exclude: # Note that the 'no-exclude' sentinel below is to prevent # an empty string value from excluding all jobs and causing From 141fd8b8943eb72317dcf1f91398cd7d9f79d6d6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 2 Feb 2026 16:57:04 +0000 Subject: [PATCH 130/133] GH-144179: Add value recording to JIT tracing front-end (GH-144303) --- .gitattributes | 1 + Include/internal/pycore_opcode_metadata.h | 132 +- Include/internal/pycore_optimizer.h | 9 +- Include/internal/pycore_uop_ids.h | 1811 +++++++++-------- Include/internal/pycore_uop_metadata.h | 28 + Makefile.pre.in | 11 +- Modules/_testinternalcapi/test_cases.c.h | 193 +- Python/bytecodes.c | 132 +- Python/executor_cases.c.h | 94 +- Python/generated_cases.c.h | 193 +- Python/optimizer.c | 24 +- Python/optimizer_bytecodes.c | 1 + Python/optimizer_cases.c.h | 29 + Python/record_functions.c.h | 115 ++ Tools/c-analyzer/cpython/_parser.py | 1 + Tools/cases_generator/analyzer.py | 15 +- Tools/cases_generator/generators_common.py | 2 + .../opcode_metadata_generator.py | 1 + .../record_function_generator.py | 134 ++ Tools/cases_generator/tier1_generator.py | 4 +- Tools/cases_generator/tier2_generator.py | 34 +- Tools/cases_generator/uop_id_generator.py | 2 + .../cases_generator/uop_metadata_generator.py | 10 +- 23 files changed, 1702 insertions(+), 1274 deletions(-) create mode 100644 Python/record_functions.c.h create mode 100644 Tools/cases_generator/record_function_generator.py diff --git a/.gitattributes b/.gitattributes index 14c1eced0cf..0dac0f84927 100644 --- a/.gitattributes +++ b/.gitattributes @@ -106,6 +106,7 @@ Python/executor_cases.c.h generated Python/generated_cases.c.h generated Python/optimizer_cases.c.h generated Python/opcode_targets.h generated +Python/record_functions.c.h generated Python/stdlib_module_names.h generated Tools/peg_generator/pegen/grammar_parser.py generated aclocal.m4 generated diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index fe94dc6a24f..db28839a860 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1050,6 +1050,7 @@ enum InstructionFormat { #define HAS_PERIODIC_FLAG (32768) #define HAS_UNPREDICTABLE_JUMP_FLAG (65536) #define HAS_NEEDS_GUARD_IP_FLAG (131072) +#define HAS_RECORDS_VALUE_FLAG (262144) #define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG)) #define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG)) #define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG)) @@ -1068,6 +1069,7 @@ enum InstructionFormat { #define OPCODE_HAS_PERIODIC(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PERIODIC_FLAG)) #define OPCODE_HAS_UNPREDICTABLE_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_UNPREDICTABLE_JUMP_FLAG)) #define OPCODE_HAS_NEEDS_GUARD_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NEEDS_GUARD_IP_FLAG)) +#define OPCODE_HAS_RECORDS_VALUE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_RECORDS_VALUE_FLAG)) #define OPARG_SIMPLE 0 #define OPARG_CACHE_1 1 @@ -1099,7 +1101,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG }, [BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_LIST_SLICE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, @@ -1118,15 +1120,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG }, [CACHE] = { true, INSTR_FMT_IX, 0 }, [CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [CALL_EX_NON_PY_GENERAL] = { true, INSTR_FMT_IXC, HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_EX_PY] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_EX_PY] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [CALL_FUNCTION_EX] = { true, INSTR_FMT_IXC, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1138,12 +1140,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [CALL_LEN] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, @@ -1177,7 +1179,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, - [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, @@ -1221,18 +1223,18 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG }, + [LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG }, [LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [LOAD_COMMON_CONSTANT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG }, @@ -1278,8 +1280,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [RESERVED] = { true, INSTR_FMT_IX, 0 }, [RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG }, - [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, - [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, + [RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1288,8 +1290,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, - [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, + [STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG }, [STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, [STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG }, @@ -1302,7 +1304,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG }, [TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, + [TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG }, [TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG }, [TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, @@ -1318,7 +1320,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1333,7 +1335,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { }; #endif -#define MAX_UOP_PER_EXPANSION 10 +#define MAX_UOP_PER_EXPANSION 11 struct opcode_macro_expansion { int nuops; struct { int16_t uop; int8_t size; int8_t offset; } uops[MAX_UOP_PER_EXPANSION]; @@ -1352,7 +1354,7 @@ _PyOpcode_macro_expansion[256] = { [BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_DICT] = { .nuops = 4, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, - [BINARY_OP_SUBSCR_GETITEM] = { .nuops = 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_GETITEM] = { .nuops = 5, .uops = { { _RECORD_TOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } }, [BINARY_OP_SUBSCR_STR_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_COMPACT_ASCII, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } }, @@ -1369,15 +1371,15 @@ _PyOpcode_macro_expansion[256] = { [BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, OPARG_SIMPLE, 0 } } }, [BUILD_TEMPLATE] = { .nuops = 1, .uops = { { _BUILD_TEMPLATE, OPARG_SIMPLE, 0 } } }, [BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, OPARG_SIMPLE, 0 } } }, - [CALL_ALLOC_AND_ENTER_INIT] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_AND_ALLOCATE_OBJECT, 2, 1 }, { _CREATE_INIT_FRAME, OPARG_SIMPLE, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 10, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_BOUND_METHOD_GENERAL] = { .nuops = 7, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_ALLOC_AND_ENTER_INIT] = { .nuops = 5, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_AND_ALLOCATE_OBJECT, 2, 1 }, { _CREATE_INIT_FRAME, OPARG_SIMPLE, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, + [CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 11, .uops = { { _RECORD_BOUND_METHOD, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, + [CALL_BOUND_METHOD_GENERAL] = { .nuops = 8, .uops = { { _RECORD_BOUND_METHOD, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, + [CALL_BUILTIN_CLASS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_FAST] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_O] = { .nuops = 5, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_EX_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CALL_FUNCTION_EX_NON_PY_GENERAL, OPARG_SIMPLE, 1 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 1 } } }, - [CALL_EX_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CHECK_IS_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _PY_FRAME_EX, OPARG_SIMPLE, 1 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, + [CALL_EX_PY] = { .nuops = 7, .uops = { { _RECORD_4OS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CHECK_IS_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _PY_FRAME_EX, OPARG_SIMPLE, 1 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } }, [CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, @@ -1387,12 +1389,12 @@ _PyOpcode_macro_expansion[256] = { [CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_LIST_APPEND] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 5, .uops = { { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_PY_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_PY_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 6, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_PY_EXACT_ARGS] = { .nuops = 9, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, + [CALL_PY_GENERAL] = { .nuops = 7, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_STR_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_TUPLE_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_TYPE_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TYPE_1, OPARG_SIMPLE, 3 }, { _CALL_TYPE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, @@ -1422,7 +1424,7 @@ _PyOpcode_macro_expansion[256] = { [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, OPARG_SIMPLE, 0 } } }, [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { _FORMAT_WITH_SPEC, OPARG_SIMPLE, 0 } } }, [FOR_ITER] = { .nuops = 1, .uops = { { _FOR_ITER, OPARG_REPLACED, 0 } } }, - [FOR_ITER_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, + [FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } }, [FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } }, [FOR_ITER_TUPLE] = { .nuops = 3, .uops = { { _ITER_CHECK_TUPLE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_TUPLE, OPARG_REPLACED, 1 }, { _ITER_NEXT_TUPLE, OPARG_SIMPLE, 1 } } }, @@ -1442,17 +1444,17 @@ _PyOpcode_macro_expansion[256] = { [LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, OPARG_SIMPLE, 0 } } }, [LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, OPARG_SIMPLE, 8 } } }, [LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 5, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, - [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_CLASS, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } }, + [LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } }, + [LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } }, [LOAD_ATTR_MODULE] = { .nuops = 4, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, - [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, - [LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_SLOT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, - [LOAD_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } }, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } }, + [LOAD_ATTR_PROPERTY] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_SLOT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, + [LOAD_ATTR_WITH_HINT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } }, [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { _LOAD_BUILD_CLASS, OPARG_SIMPLE, 0 } } }, [LOAD_COMMON_CONSTANT] = { .nuops = 1, .uops = { { _LOAD_COMMON_CONSTANT, OPARG_SIMPLE, 0 } } }, [LOAD_CONST] = { .nuops = 1, .uops = { { _LOAD_CONST, OPARG_SIMPLE, 0 } } }, @@ -1492,8 +1494,8 @@ _PyOpcode_macro_expansion[256] = { [PUSH_EXC_INFO] = { .nuops = 1, .uops = { { _PUSH_EXC_INFO, OPARG_SIMPLE, 0 } } }, [PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, OPARG_SIMPLE, 0 } } }, [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 0 } } }, - [RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } }, - [RETURN_VALUE] = { .nuops = 1, .uops = { { _RETURN_VALUE, OPARG_SIMPLE, 0 } } }, + [RETURN_GENERATOR] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } }, + [RETURN_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } }, [SEND_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, OPARG_SIMPLE, 0 } } }, [SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, OPARG_SIMPLE, 0 } } }, @@ -1501,8 +1503,8 @@ _PyOpcode_macro_expansion[256] = { [SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, OPARG_SIMPLE, 0 } } }, [STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, OPARG_SIMPLE, 3 } } }, [STORE_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, - [STORE_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, - [STORE_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, + [STORE_ATTR_SLOT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, + [STORE_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } }, [STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, OPARG_SIMPLE, 0 } } }, [STORE_FAST] = { .nuops = 2, .uops = { { _SWAP_FAST, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 } } }, [STORE_FAST_LOAD_FAST] = { .nuops = 3, .uops = { { _SWAP_FAST, OPARG_TOP, 0 }, { _POP_TOP, OPARG_TOP, 0 }, { _LOAD_FAST, OPARG_BOTTOM, 0 } } }, @@ -1515,7 +1517,7 @@ _PyOpcode_macro_expansion[256] = { [STORE_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } }, [SWAP] = { .nuops = 1, .uops = { { _SWAP, OPARG_SIMPLE, 0 } } }, [TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, OPARG_SIMPLE, 2 } } }, - [TO_BOOL_ALWAYS_TRUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, + [TO_BOOL_ALWAYS_TRUE] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL_BOOL, OPARG_SIMPLE, 3 } } }, [TO_BOOL_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _TO_BOOL_INT, OPARG_SIMPLE, 3 }, { _POP_TOP_INT, OPARG_SIMPLE, 3 } } }, [TO_BOOL_LIST] = { .nuops = 3, .uops = { { _GUARD_TOS_LIST, OPARG_SIMPLE, 0 }, { _TO_BOOL_LIST, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, @@ -1530,7 +1532,7 @@ _PyOpcode_macro_expansion[256] = { [UNPACK_SEQUENCE_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 } } }, [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 } } }, [WITH_EXCEPT_START] = { .nuops = 1, .uops = { { _WITH_EXCEPT_START, OPARG_SIMPLE, 0 } } }, - [YIELD_VALUE] = { .nuops = 1, .uops = { { _YIELD_VALUE, OPARG_SIMPLE, 0 } } }, + [YIELD_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _YIELD_VALUE, OPARG_SIMPLE, 0 } } }, }; #endif // NEED_OPCODE_METADATA diff --git a/Include/internal/pycore_optimizer.h b/Include/internal/pycore_optimizer.h index 2ee518fb82f..bb2028c5935 100644 --- a/Include/internal/pycore_optimizer.h +++ b/Include/internal/pycore_optimizer.h @@ -90,6 +90,7 @@ typedef struct _PyJitTracerPreviousState { PyCodeObject *instr_code; // Strong struct _PyInterpreterFrame *instr_frame; _PyBloomFilter dependencies; + PyObject *recorded_value; // Strong, may be NULL } _PyJitTracerPreviousState; typedef struct _PyJitTracerTranslatorState { @@ -336,7 +337,7 @@ PyAPI_FUNC(int) _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate, PyAPI_FUNC(int) _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr, _Py_CODEUNIT *start_instr, - _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, + _Py_CODEUNIT *close_loop_instr, _PyStackRef *stack_pointer, int chain_depth, _PyExitData *exit, int oparg, _PyExecutorObject *current_executor); PyAPI_FUNC(void) _PyJit_FinalizeTracing(PyThreadState *tstate, int err); @@ -344,6 +345,12 @@ void _PyJit_TracerFree(_PyThreadStateImpl *_tstate); void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj); +#ifdef _Py_TIER2 +typedef void (*_Py_RecordFuncPtr)(_PyInterpreterFrame *frame, _PyStackRef *stackpointer, int oparg, PyObject **recorded_value); +PyAPI_DATA(const _Py_RecordFuncPtr) _PyOpcode_RecordFunctions[]; +PyAPI_DATA(const uint8_t) _PyOpcode_RecordFunctionIndices[256]; +#endif + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index 8712d1afc75..850ae446dc7 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -323,922 +323,929 @@ extern "C" { #define _PY_FRAME_GENERAL 538 #define _PY_FRAME_KW 539 #define _QUICKEN_RESUME 540 -#define _REPLACE_WITH_TRUE 541 +#define _RECORD_4OS 541 +#define _RECORD_BOUND_METHOD 542 +#define _RECORD_CALLABLE 543 +#define _RECORD_CALLER_CODE 544 +#define _RECORD_NOS 545 +#define _RECORD_TOS 546 +#define _RECORD_TOS_TYPE 547 +#define _REPLACE_WITH_TRUE 548 #define _RESUME_CHECK RESUME_CHECK -#define _RETURN_GENERATOR RETURN_GENERATOR -#define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 542 -#define _SEND 543 -#define _SEND_GEN_FRAME 544 +#define _RETURN_GENERATOR 549 +#define _RETURN_VALUE 550 +#define _SAVE_RETURN_OFFSET 551 +#define _SEND 552 +#define _SEND_GEN_FRAME 553 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 545 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 546 -#define _SPILL_OR_RELOAD 547 -#define _START_EXECUTOR 548 -#define _STORE_ATTR 549 -#define _STORE_ATTR_INSTANCE_VALUE 550 -#define _STORE_ATTR_SLOT 551 -#define _STORE_ATTR_WITH_HINT 552 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW 554 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW 555 +#define _SPILL_OR_RELOAD 556 +#define _START_EXECUTOR 557 +#define _STORE_ATTR 558 +#define _STORE_ATTR_INSTANCE_VALUE 559 +#define _STORE_ATTR_SLOT 560 +#define _STORE_ATTR_WITH_HINT 561 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 553 -#define _STORE_SUBSCR 554 -#define _STORE_SUBSCR_DICT 555 -#define _STORE_SUBSCR_LIST_INT 556 -#define _SWAP 557 -#define _SWAP_2 558 -#define _SWAP_3 559 -#define _SWAP_FAST 560 -#define _SWAP_FAST_0 561 -#define _SWAP_FAST_1 562 -#define _SWAP_FAST_2 563 -#define _SWAP_FAST_3 564 -#define _SWAP_FAST_4 565 -#define _SWAP_FAST_5 566 -#define _SWAP_FAST_6 567 -#define _SWAP_FAST_7 568 -#define _TIER2_RESUME_CHECK 569 -#define _TO_BOOL 570 +#define _STORE_SLICE 562 +#define _STORE_SUBSCR 563 +#define _STORE_SUBSCR_DICT 564 +#define _STORE_SUBSCR_LIST_INT 565 +#define _SWAP 566 +#define _SWAP_2 567 +#define _SWAP_3 568 +#define _SWAP_FAST 569 +#define _SWAP_FAST_0 570 +#define _SWAP_FAST_1 571 +#define _SWAP_FAST_2 572 +#define _SWAP_FAST_3 573 +#define _SWAP_FAST_4 574 +#define _SWAP_FAST_5 575 +#define _SWAP_FAST_6 576 +#define _SWAP_FAST_7 577 +#define _TIER2_RESUME_CHECK 578 +#define _TO_BOOL 579 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 571 -#define _TO_BOOL_LIST 572 +#define _TO_BOOL_INT 580 +#define _TO_BOOL_LIST 581 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 573 +#define _TO_BOOL_STR 582 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 574 -#define _UNARY_NEGATIVE 575 +#define _UNARY_INVERT 583 +#define _UNARY_NEGATIVE 584 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 576 -#define _UNPACK_SEQUENCE_LIST 577 -#define _UNPACK_SEQUENCE_TUPLE 578 -#define _UNPACK_SEQUENCE_TWO_TUPLE 579 +#define _UNPACK_SEQUENCE 585 +#define _UNPACK_SEQUENCE_LIST 586 +#define _UNPACK_SEQUENCE_TUPLE 587 +#define _UNPACK_SEQUENCE_TWO_TUPLE 588 #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 579 -#define _BINARY_OP_r23 580 -#define _BINARY_OP_ADD_FLOAT_r03 581 -#define _BINARY_OP_ADD_FLOAT_r13 582 -#define _BINARY_OP_ADD_FLOAT_r23 583 -#define _BINARY_OP_ADD_INT_r03 584 -#define _BINARY_OP_ADD_INT_r13 585 -#define _BINARY_OP_ADD_INT_r23 586 -#define _BINARY_OP_ADD_UNICODE_r03 587 -#define _BINARY_OP_ADD_UNICODE_r13 588 -#define _BINARY_OP_ADD_UNICODE_r23 589 -#define _BINARY_OP_EXTEND_r23 590 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 591 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 592 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 593 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 594 -#define _BINARY_OP_MULTIPLY_INT_r03 595 -#define _BINARY_OP_MULTIPLY_INT_r13 596 -#define _BINARY_OP_MULTIPLY_INT_r23 597 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 598 -#define _BINARY_OP_SUBSCR_DICT_r23 599 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 600 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 601 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 602 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 603 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 604 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 605 -#define _BINARY_OP_SUBSCR_STR_INT_r23 606 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 607 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 608 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 609 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 610 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 611 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 612 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 613 -#define _BINARY_OP_SUBTRACT_INT_r03 614 -#define _BINARY_OP_SUBTRACT_INT_r13 615 -#define _BINARY_OP_SUBTRACT_INT_r23 616 -#define _BINARY_SLICE_r31 617 -#define _BUILD_INTERPOLATION_r01 618 -#define _BUILD_LIST_r01 619 -#define _BUILD_MAP_r01 620 -#define _BUILD_SET_r01 621 -#define _BUILD_SLICE_r01 622 -#define _BUILD_STRING_r01 623 -#define _BUILD_TEMPLATE_r21 624 -#define _BUILD_TUPLE_r01 625 -#define _CALL_BUILTIN_CLASS_r01 626 -#define _CALL_BUILTIN_FAST_r01 627 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 628 -#define _CALL_BUILTIN_O_r03 629 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 630 -#define _CALL_INTRINSIC_1_r11 631 -#define _CALL_INTRINSIC_2_r21 632 -#define _CALL_ISINSTANCE_r31 633 -#define _CALL_KW_NON_PY_r11 634 -#define _CALL_LEN_r33 635 -#define _CALL_LIST_APPEND_r03 636 -#define _CALL_LIST_APPEND_r13 637 -#define _CALL_LIST_APPEND_r23 638 -#define _CALL_LIST_APPEND_r33 639 -#define _CALL_METHOD_DESCRIPTOR_FAST_r01 640 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 641 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 642 -#define _CALL_METHOD_DESCRIPTOR_O_r03 643 -#define _CALL_NON_PY_GENERAL_r01 644 -#define _CALL_STR_1_r32 645 -#define _CALL_TUPLE_1_r32 646 -#define _CALL_TYPE_1_r02 647 -#define _CALL_TYPE_1_r12 648 -#define _CALL_TYPE_1_r22 649 -#define _CALL_TYPE_1_r32 650 -#define _CHECK_AND_ALLOCATE_OBJECT_r00 651 -#define _CHECK_ATTR_CLASS_r01 652 -#define _CHECK_ATTR_CLASS_r11 653 -#define _CHECK_ATTR_CLASS_r22 654 -#define _CHECK_ATTR_CLASS_r33 655 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 656 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 657 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 658 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 659 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 660 -#define _CHECK_EG_MATCH_r22 661 -#define _CHECK_EXC_MATCH_r22 662 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 663 -#define _CHECK_FUNCTION_VERSION_r00 664 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 665 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 666 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 667 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 668 -#define _CHECK_FUNCTION_VERSION_KW_r11 669 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 670 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 671 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 672 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 673 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 674 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 675 -#define _CHECK_IS_PY_CALLABLE_EX_r03 676 -#define _CHECK_IS_PY_CALLABLE_EX_r13 677 -#define _CHECK_IS_PY_CALLABLE_EX_r23 678 -#define _CHECK_IS_PY_CALLABLE_EX_r33 679 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 680 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 681 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 682 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 683 -#define _CHECK_METHOD_VERSION_r00 684 -#define _CHECK_METHOD_VERSION_KW_r11 685 -#define _CHECK_PEP_523_r00 686 -#define _CHECK_PEP_523_r11 687 -#define _CHECK_PEP_523_r22 688 -#define _CHECK_PEP_523_r33 689 -#define _CHECK_PERIODIC_r00 690 -#define _CHECK_PERIODIC_AT_END_r00 691 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 692 -#define _CHECK_RECURSION_REMAINING_r00 693 -#define _CHECK_RECURSION_REMAINING_r11 694 -#define _CHECK_RECURSION_REMAINING_r22 695 -#define _CHECK_RECURSION_REMAINING_r33 696 -#define _CHECK_STACK_SPACE_r00 697 -#define _CHECK_STACK_SPACE_OPERAND_r00 698 -#define _CHECK_STACK_SPACE_OPERAND_r11 699 -#define _CHECK_STACK_SPACE_OPERAND_r22 700 -#define _CHECK_STACK_SPACE_OPERAND_r33 701 -#define _CHECK_VALIDITY_r00 702 -#define _CHECK_VALIDITY_r11 703 -#define _CHECK_VALIDITY_r22 704 -#define _CHECK_VALIDITY_r33 705 -#define _COLD_DYNAMIC_EXIT_r00 706 -#define _COLD_EXIT_r00 707 -#define _COMPARE_OP_r21 708 -#define _COMPARE_OP_FLOAT_r03 709 -#define _COMPARE_OP_FLOAT_r13 710 -#define _COMPARE_OP_FLOAT_r23 711 -#define _COMPARE_OP_INT_r23 712 -#define _COMPARE_OP_STR_r23 713 -#define _CONTAINS_OP_r23 714 -#define _CONTAINS_OP_DICT_r23 715 -#define _CONTAINS_OP_SET_r23 716 -#define _CONVERT_VALUE_r11 717 -#define _COPY_r01 718 -#define _COPY_1_r02 719 -#define _COPY_1_r12 720 -#define _COPY_1_r23 721 -#define _COPY_2_r03 722 -#define _COPY_2_r13 723 -#define _COPY_2_r23 724 -#define _COPY_3_r03 725 -#define _COPY_3_r13 726 -#define _COPY_3_r23 727 -#define _COPY_3_r33 728 -#define _COPY_FREE_VARS_r00 729 -#define _COPY_FREE_VARS_r11 730 -#define _COPY_FREE_VARS_r22 731 -#define _COPY_FREE_VARS_r33 732 -#define _CREATE_INIT_FRAME_r01 733 -#define _DELETE_ATTR_r10 734 -#define _DELETE_DEREF_r00 735 -#define _DELETE_FAST_r00 736 -#define _DELETE_GLOBAL_r00 737 -#define _DELETE_NAME_r00 738 -#define _DELETE_SUBSCR_r20 739 -#define _DEOPT_r00 740 -#define _DEOPT_r10 741 -#define _DEOPT_r20 742 -#define _DEOPT_r30 743 -#define _DICT_MERGE_r10 744 -#define _DICT_UPDATE_r10 745 -#define _DO_CALL_r01 746 -#define _DO_CALL_FUNCTION_EX_r31 747 -#define _DO_CALL_KW_r11 748 -#define _DYNAMIC_EXIT_r00 749 -#define _DYNAMIC_EXIT_r10 750 -#define _DYNAMIC_EXIT_r20 751 -#define _DYNAMIC_EXIT_r30 752 -#define _END_FOR_r10 753 -#define _END_SEND_r21 754 -#define _ERROR_POP_N_r00 755 -#define _EXIT_INIT_CHECK_r10 756 -#define _EXIT_TRACE_r00 757 -#define _EXIT_TRACE_r10 758 -#define _EXIT_TRACE_r20 759 -#define _EXIT_TRACE_r30 760 -#define _EXPAND_METHOD_r00 761 -#define _EXPAND_METHOD_KW_r11 762 -#define _FATAL_ERROR_r00 763 -#define _FATAL_ERROR_r11 764 -#define _FATAL_ERROR_r22 765 -#define _FATAL_ERROR_r33 766 -#define _FORMAT_SIMPLE_r11 767 -#define _FORMAT_WITH_SPEC_r21 768 -#define _FOR_ITER_r23 769 -#define _FOR_ITER_GEN_FRAME_r03 770 -#define _FOR_ITER_GEN_FRAME_r13 771 -#define _FOR_ITER_GEN_FRAME_r23 772 -#define _FOR_ITER_TIER_TWO_r23 773 -#define _GET_AITER_r11 774 -#define _GET_ANEXT_r12 775 -#define _GET_AWAITABLE_r11 776 -#define _GET_ITER_r12 777 -#define _GET_LEN_r12 778 -#define _GET_YIELD_FROM_ITER_r11 779 -#define _GUARD_BINARY_OP_EXTEND_r22 780 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 781 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 782 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 783 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 784 -#define _GUARD_BIT_IS_SET_POP_r00 785 -#define _GUARD_BIT_IS_SET_POP_r10 786 -#define _GUARD_BIT_IS_SET_POP_r21 787 -#define _GUARD_BIT_IS_SET_POP_r32 788 -#define _GUARD_BIT_IS_SET_POP_4_r00 789 -#define _GUARD_BIT_IS_SET_POP_4_r10 790 -#define _GUARD_BIT_IS_SET_POP_4_r21 791 -#define _GUARD_BIT_IS_SET_POP_4_r32 792 -#define _GUARD_BIT_IS_SET_POP_5_r00 793 -#define _GUARD_BIT_IS_SET_POP_5_r10 794 -#define _GUARD_BIT_IS_SET_POP_5_r21 795 -#define _GUARD_BIT_IS_SET_POP_5_r32 796 -#define _GUARD_BIT_IS_SET_POP_6_r00 797 -#define _GUARD_BIT_IS_SET_POP_6_r10 798 -#define _GUARD_BIT_IS_SET_POP_6_r21 799 -#define _GUARD_BIT_IS_SET_POP_6_r32 800 -#define _GUARD_BIT_IS_SET_POP_7_r00 801 -#define _GUARD_BIT_IS_SET_POP_7_r10 802 -#define _GUARD_BIT_IS_SET_POP_7_r21 803 -#define _GUARD_BIT_IS_SET_POP_7_r32 804 -#define _GUARD_BIT_IS_UNSET_POP_r00 805 -#define _GUARD_BIT_IS_UNSET_POP_r10 806 -#define _GUARD_BIT_IS_UNSET_POP_r21 807 -#define _GUARD_BIT_IS_UNSET_POP_r32 808 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 809 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 810 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 811 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 812 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 813 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 814 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 815 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 816 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 817 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 818 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 819 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 820 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 821 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 822 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 823 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 824 -#define _GUARD_CALLABLE_ISINSTANCE_r03 825 -#define _GUARD_CALLABLE_ISINSTANCE_r13 826 -#define _GUARD_CALLABLE_ISINSTANCE_r23 827 -#define _GUARD_CALLABLE_ISINSTANCE_r33 828 -#define _GUARD_CALLABLE_LEN_r03 829 -#define _GUARD_CALLABLE_LEN_r13 830 -#define _GUARD_CALLABLE_LEN_r23 831 -#define _GUARD_CALLABLE_LEN_r33 832 -#define _GUARD_CALLABLE_LIST_APPEND_r03 833 -#define _GUARD_CALLABLE_LIST_APPEND_r13 834 -#define _GUARD_CALLABLE_LIST_APPEND_r23 835 -#define _GUARD_CALLABLE_LIST_APPEND_r33 836 -#define _GUARD_CALLABLE_STR_1_r03 837 -#define _GUARD_CALLABLE_STR_1_r13 838 -#define _GUARD_CALLABLE_STR_1_r23 839 -#define _GUARD_CALLABLE_STR_1_r33 840 -#define _GUARD_CALLABLE_TUPLE_1_r03 841 -#define _GUARD_CALLABLE_TUPLE_1_r13 842 -#define _GUARD_CALLABLE_TUPLE_1_r23 843 -#define _GUARD_CALLABLE_TUPLE_1_r33 844 -#define _GUARD_CALLABLE_TYPE_1_r03 845 -#define _GUARD_CALLABLE_TYPE_1_r13 846 -#define _GUARD_CALLABLE_TYPE_1_r23 847 -#define _GUARD_CALLABLE_TYPE_1_r33 848 -#define _GUARD_DORV_NO_DICT_r01 849 -#define _GUARD_DORV_NO_DICT_r11 850 -#define _GUARD_DORV_NO_DICT_r22 851 -#define _GUARD_DORV_NO_DICT_r33 852 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 853 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 854 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 855 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 856 -#define _GUARD_GLOBALS_VERSION_r00 857 -#define _GUARD_GLOBALS_VERSION_r11 858 -#define _GUARD_GLOBALS_VERSION_r22 859 -#define _GUARD_GLOBALS_VERSION_r33 860 -#define _GUARD_IP_RETURN_GENERATOR_r00 861 -#define _GUARD_IP_RETURN_GENERATOR_r11 862 -#define _GUARD_IP_RETURN_GENERATOR_r22 863 -#define _GUARD_IP_RETURN_GENERATOR_r33 864 -#define _GUARD_IP_RETURN_VALUE_r00 865 -#define _GUARD_IP_RETURN_VALUE_r11 866 -#define _GUARD_IP_RETURN_VALUE_r22 867 -#define _GUARD_IP_RETURN_VALUE_r33 868 -#define _GUARD_IP_YIELD_VALUE_r00 869 -#define _GUARD_IP_YIELD_VALUE_r11 870 -#define _GUARD_IP_YIELD_VALUE_r22 871 -#define _GUARD_IP_YIELD_VALUE_r33 872 -#define _GUARD_IP__PUSH_FRAME_r00 873 -#define _GUARD_IP__PUSH_FRAME_r11 874 -#define _GUARD_IP__PUSH_FRAME_r22 875 -#define _GUARD_IP__PUSH_FRAME_r33 876 -#define _GUARD_IS_FALSE_POP_r00 877 -#define _GUARD_IS_FALSE_POP_r10 878 -#define _GUARD_IS_FALSE_POP_r21 879 -#define _GUARD_IS_FALSE_POP_r32 880 -#define _GUARD_IS_NONE_POP_r00 881 -#define _GUARD_IS_NONE_POP_r10 882 -#define _GUARD_IS_NONE_POP_r21 883 -#define _GUARD_IS_NONE_POP_r32 884 -#define _GUARD_IS_NOT_NONE_POP_r10 885 -#define _GUARD_IS_TRUE_POP_r00 886 -#define _GUARD_IS_TRUE_POP_r10 887 -#define _GUARD_IS_TRUE_POP_r21 888 -#define _GUARD_IS_TRUE_POP_r32 889 -#define _GUARD_KEYS_VERSION_r01 890 -#define _GUARD_KEYS_VERSION_r11 891 -#define _GUARD_KEYS_VERSION_r22 892 -#define _GUARD_KEYS_VERSION_r33 893 -#define _GUARD_NOS_COMPACT_ASCII_r02 894 -#define _GUARD_NOS_COMPACT_ASCII_r12 895 -#define _GUARD_NOS_COMPACT_ASCII_r22 896 -#define _GUARD_NOS_COMPACT_ASCII_r33 897 -#define _GUARD_NOS_DICT_r02 898 -#define _GUARD_NOS_DICT_r12 899 -#define _GUARD_NOS_DICT_r22 900 -#define _GUARD_NOS_DICT_r33 901 -#define _GUARD_NOS_FLOAT_r02 902 -#define _GUARD_NOS_FLOAT_r12 903 -#define _GUARD_NOS_FLOAT_r22 904 -#define _GUARD_NOS_FLOAT_r33 905 -#define _GUARD_NOS_INT_r02 906 -#define _GUARD_NOS_INT_r12 907 -#define _GUARD_NOS_INT_r22 908 -#define _GUARD_NOS_INT_r33 909 -#define _GUARD_NOS_LIST_r02 910 -#define _GUARD_NOS_LIST_r12 911 -#define _GUARD_NOS_LIST_r22 912 -#define _GUARD_NOS_LIST_r33 913 -#define _GUARD_NOS_NOT_NULL_r02 914 -#define _GUARD_NOS_NOT_NULL_r12 915 -#define _GUARD_NOS_NOT_NULL_r22 916 -#define _GUARD_NOS_NOT_NULL_r33 917 -#define _GUARD_NOS_NULL_r02 918 -#define _GUARD_NOS_NULL_r12 919 -#define _GUARD_NOS_NULL_r22 920 -#define _GUARD_NOS_NULL_r33 921 -#define _GUARD_NOS_OVERFLOWED_r02 922 -#define _GUARD_NOS_OVERFLOWED_r12 923 -#define _GUARD_NOS_OVERFLOWED_r22 924 -#define _GUARD_NOS_OVERFLOWED_r33 925 -#define _GUARD_NOS_TUPLE_r02 926 -#define _GUARD_NOS_TUPLE_r12 927 -#define _GUARD_NOS_TUPLE_r22 928 -#define _GUARD_NOS_TUPLE_r33 929 -#define _GUARD_NOS_UNICODE_r02 930 -#define _GUARD_NOS_UNICODE_r12 931 -#define _GUARD_NOS_UNICODE_r22 932 -#define _GUARD_NOS_UNICODE_r33 933 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 934 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 935 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 936 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 937 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 938 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 939 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 940 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 941 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 942 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 943 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 944 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 945 -#define _GUARD_THIRD_NULL_r03 946 -#define _GUARD_THIRD_NULL_r13 947 -#define _GUARD_THIRD_NULL_r23 948 -#define _GUARD_THIRD_NULL_r33 949 -#define _GUARD_TOS_ANY_SET_r01 950 -#define _GUARD_TOS_ANY_SET_r11 951 -#define _GUARD_TOS_ANY_SET_r22 952 -#define _GUARD_TOS_ANY_SET_r33 953 -#define _GUARD_TOS_DICT_r01 954 -#define _GUARD_TOS_DICT_r11 955 -#define _GUARD_TOS_DICT_r22 956 -#define _GUARD_TOS_DICT_r33 957 -#define _GUARD_TOS_FLOAT_r01 958 -#define _GUARD_TOS_FLOAT_r11 959 -#define _GUARD_TOS_FLOAT_r22 960 -#define _GUARD_TOS_FLOAT_r33 961 -#define _GUARD_TOS_INT_r01 962 -#define _GUARD_TOS_INT_r11 963 -#define _GUARD_TOS_INT_r22 964 -#define _GUARD_TOS_INT_r33 965 -#define _GUARD_TOS_LIST_r01 966 -#define _GUARD_TOS_LIST_r11 967 -#define _GUARD_TOS_LIST_r22 968 -#define _GUARD_TOS_LIST_r33 969 -#define _GUARD_TOS_OVERFLOWED_r01 970 -#define _GUARD_TOS_OVERFLOWED_r11 971 -#define _GUARD_TOS_OVERFLOWED_r22 972 -#define _GUARD_TOS_OVERFLOWED_r33 973 -#define _GUARD_TOS_SLICE_r01 974 -#define _GUARD_TOS_SLICE_r11 975 -#define _GUARD_TOS_SLICE_r22 976 -#define _GUARD_TOS_SLICE_r33 977 -#define _GUARD_TOS_TUPLE_r01 978 -#define _GUARD_TOS_TUPLE_r11 979 -#define _GUARD_TOS_TUPLE_r22 980 -#define _GUARD_TOS_TUPLE_r33 981 -#define _GUARD_TOS_UNICODE_r01 982 -#define _GUARD_TOS_UNICODE_r11 983 -#define _GUARD_TOS_UNICODE_r22 984 -#define _GUARD_TOS_UNICODE_r33 985 -#define _GUARD_TYPE_VERSION_r01 986 -#define _GUARD_TYPE_VERSION_r11 987 -#define _GUARD_TYPE_VERSION_r22 988 -#define _GUARD_TYPE_VERSION_r33 989 -#define _GUARD_TYPE_VERSION_AND_LOCK_r01 990 -#define _GUARD_TYPE_VERSION_AND_LOCK_r11 991 -#define _GUARD_TYPE_VERSION_AND_LOCK_r22 992 -#define _GUARD_TYPE_VERSION_AND_LOCK_r33 993 -#define _HANDLE_PENDING_AND_DEOPT_r00 994 -#define _HANDLE_PENDING_AND_DEOPT_r10 995 -#define _HANDLE_PENDING_AND_DEOPT_r20 996 -#define _HANDLE_PENDING_AND_DEOPT_r30 997 -#define _IMPORT_FROM_r12 998 -#define _IMPORT_NAME_r21 999 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1000 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1001 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1002 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1003 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1004 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1005 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1006 -#define _INSERT_1_LOAD_CONST_INLINE_r02 1007 -#define _INSERT_1_LOAD_CONST_INLINE_r12 1008 -#define _INSERT_1_LOAD_CONST_INLINE_r23 1009 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1010 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1011 -#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1012 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1013 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1014 -#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1015 -#define _INSERT_NULL_r10 1016 -#define _INSTRUMENTED_FOR_ITER_r23 1017 -#define _INSTRUMENTED_INSTRUCTION_r00 1018 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1019 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1020 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1021 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1022 -#define _INSTRUMENTED_LINE_r00 1023 -#define _INSTRUMENTED_NOT_TAKEN_r00 1024 -#define _INSTRUMENTED_NOT_TAKEN_r11 1025 -#define _INSTRUMENTED_NOT_TAKEN_r22 1026 -#define _INSTRUMENTED_NOT_TAKEN_r33 1027 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1028 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1029 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1030 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1031 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1032 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1033 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1034 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1035 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1036 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1037 -#define _IS_NONE_r11 1038 -#define _IS_OP_r03 1039 -#define _IS_OP_r13 1040 -#define _IS_OP_r23 1041 -#define _ITER_CHECK_LIST_r02 1042 -#define _ITER_CHECK_LIST_r12 1043 -#define _ITER_CHECK_LIST_r22 1044 -#define _ITER_CHECK_LIST_r33 1045 -#define _ITER_CHECK_RANGE_r02 1046 -#define _ITER_CHECK_RANGE_r12 1047 -#define _ITER_CHECK_RANGE_r22 1048 -#define _ITER_CHECK_RANGE_r33 1049 -#define _ITER_CHECK_TUPLE_r02 1050 -#define _ITER_CHECK_TUPLE_r12 1051 -#define _ITER_CHECK_TUPLE_r22 1052 -#define _ITER_CHECK_TUPLE_r33 1053 -#define _ITER_JUMP_LIST_r02 1054 -#define _ITER_JUMP_LIST_r12 1055 -#define _ITER_JUMP_LIST_r22 1056 -#define _ITER_JUMP_LIST_r33 1057 -#define _ITER_JUMP_RANGE_r02 1058 -#define _ITER_JUMP_RANGE_r12 1059 -#define _ITER_JUMP_RANGE_r22 1060 -#define _ITER_JUMP_RANGE_r33 1061 -#define _ITER_JUMP_TUPLE_r02 1062 -#define _ITER_JUMP_TUPLE_r12 1063 -#define _ITER_JUMP_TUPLE_r22 1064 -#define _ITER_JUMP_TUPLE_r33 1065 -#define _ITER_NEXT_LIST_r23 1066 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1067 -#define _ITER_NEXT_RANGE_r03 1068 -#define _ITER_NEXT_RANGE_r13 1069 -#define _ITER_NEXT_RANGE_r23 1070 -#define _ITER_NEXT_TUPLE_r03 1071 -#define _ITER_NEXT_TUPLE_r13 1072 -#define _ITER_NEXT_TUPLE_r23 1073 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1074 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1075 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1076 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1077 -#define _JUMP_TO_TOP_r00 1078 -#define _LIST_APPEND_r10 1079 -#define _LIST_EXTEND_r10 1080 -#define _LOAD_ATTR_r10 1081 -#define _LOAD_ATTR_CLASS_r11 1082 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1083 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1084 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1085 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1086 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1087 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1088 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1089 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1090 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1091 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1092 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1093 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1094 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1095 -#define _LOAD_ATTR_MODULE_r12 1096 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1097 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1098 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1099 -#define _LOAD_ATTR_SLOT_r02 1100 -#define _LOAD_ATTR_SLOT_r12 1101 -#define _LOAD_ATTR_SLOT_r23 1102 -#define _LOAD_ATTR_WITH_HINT_r12 1103 -#define _LOAD_BUILD_CLASS_r01 1104 -#define _LOAD_BYTECODE_r00 1105 -#define _LOAD_COMMON_CONSTANT_r01 1106 -#define _LOAD_COMMON_CONSTANT_r12 1107 -#define _LOAD_COMMON_CONSTANT_r23 1108 -#define _LOAD_CONST_r01 1109 -#define _LOAD_CONST_r12 1110 -#define _LOAD_CONST_r23 1111 -#define _LOAD_CONST_INLINE_r01 1112 -#define _LOAD_CONST_INLINE_r12 1113 -#define _LOAD_CONST_INLINE_r23 1114 -#define _LOAD_CONST_INLINE_BORROW_r01 1115 -#define _LOAD_CONST_INLINE_BORROW_r12 1116 -#define _LOAD_CONST_INLINE_BORROW_r23 1117 -#define _LOAD_CONST_UNDER_INLINE_r02 1118 -#define _LOAD_CONST_UNDER_INLINE_r12 1119 -#define _LOAD_CONST_UNDER_INLINE_r23 1120 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1121 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1122 -#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1123 -#define _LOAD_DEREF_r01 1124 -#define _LOAD_FAST_r01 1125 -#define _LOAD_FAST_r12 1126 -#define _LOAD_FAST_r23 1127 -#define _LOAD_FAST_0_r01 1128 -#define _LOAD_FAST_0_r12 1129 -#define _LOAD_FAST_0_r23 1130 -#define _LOAD_FAST_1_r01 1131 -#define _LOAD_FAST_1_r12 1132 -#define _LOAD_FAST_1_r23 1133 -#define _LOAD_FAST_2_r01 1134 -#define _LOAD_FAST_2_r12 1135 -#define _LOAD_FAST_2_r23 1136 -#define _LOAD_FAST_3_r01 1137 -#define _LOAD_FAST_3_r12 1138 -#define _LOAD_FAST_3_r23 1139 -#define _LOAD_FAST_4_r01 1140 -#define _LOAD_FAST_4_r12 1141 -#define _LOAD_FAST_4_r23 1142 -#define _LOAD_FAST_5_r01 1143 -#define _LOAD_FAST_5_r12 1144 -#define _LOAD_FAST_5_r23 1145 -#define _LOAD_FAST_6_r01 1146 -#define _LOAD_FAST_6_r12 1147 -#define _LOAD_FAST_6_r23 1148 -#define _LOAD_FAST_7_r01 1149 -#define _LOAD_FAST_7_r12 1150 -#define _LOAD_FAST_7_r23 1151 -#define _LOAD_FAST_AND_CLEAR_r01 1152 -#define _LOAD_FAST_AND_CLEAR_r12 1153 -#define _LOAD_FAST_AND_CLEAR_r23 1154 -#define _LOAD_FAST_BORROW_r01 1155 -#define _LOAD_FAST_BORROW_r12 1156 -#define _LOAD_FAST_BORROW_r23 1157 -#define _LOAD_FAST_BORROW_0_r01 1158 -#define _LOAD_FAST_BORROW_0_r12 1159 -#define _LOAD_FAST_BORROW_0_r23 1160 -#define _LOAD_FAST_BORROW_1_r01 1161 -#define _LOAD_FAST_BORROW_1_r12 1162 -#define _LOAD_FAST_BORROW_1_r23 1163 -#define _LOAD_FAST_BORROW_2_r01 1164 -#define _LOAD_FAST_BORROW_2_r12 1165 -#define _LOAD_FAST_BORROW_2_r23 1166 -#define _LOAD_FAST_BORROW_3_r01 1167 -#define _LOAD_FAST_BORROW_3_r12 1168 -#define _LOAD_FAST_BORROW_3_r23 1169 -#define _LOAD_FAST_BORROW_4_r01 1170 -#define _LOAD_FAST_BORROW_4_r12 1171 -#define _LOAD_FAST_BORROW_4_r23 1172 -#define _LOAD_FAST_BORROW_5_r01 1173 -#define _LOAD_FAST_BORROW_5_r12 1174 -#define _LOAD_FAST_BORROW_5_r23 1175 -#define _LOAD_FAST_BORROW_6_r01 1176 -#define _LOAD_FAST_BORROW_6_r12 1177 -#define _LOAD_FAST_BORROW_6_r23 1178 -#define _LOAD_FAST_BORROW_7_r01 1179 -#define _LOAD_FAST_BORROW_7_r12 1180 -#define _LOAD_FAST_BORROW_7_r23 1181 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1182 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1183 -#define _LOAD_FAST_CHECK_r01 1184 -#define _LOAD_FAST_CHECK_r12 1185 -#define _LOAD_FAST_CHECK_r23 1186 -#define _LOAD_FAST_LOAD_FAST_r02 1187 -#define _LOAD_FAST_LOAD_FAST_r13 1188 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1189 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1190 -#define _LOAD_GLOBAL_r00 1191 -#define _LOAD_GLOBAL_BUILTINS_r01 1192 -#define _LOAD_GLOBAL_MODULE_r01 1193 -#define _LOAD_LOCALS_r01 1194 -#define _LOAD_LOCALS_r12 1195 -#define _LOAD_LOCALS_r23 1196 -#define _LOAD_NAME_r01 1197 -#define _LOAD_SMALL_INT_r01 1198 -#define _LOAD_SMALL_INT_r12 1199 -#define _LOAD_SMALL_INT_r23 1200 -#define _LOAD_SMALL_INT_0_r01 1201 -#define _LOAD_SMALL_INT_0_r12 1202 -#define _LOAD_SMALL_INT_0_r23 1203 -#define _LOAD_SMALL_INT_1_r01 1204 -#define _LOAD_SMALL_INT_1_r12 1205 -#define _LOAD_SMALL_INT_1_r23 1206 -#define _LOAD_SMALL_INT_2_r01 1207 -#define _LOAD_SMALL_INT_2_r12 1208 -#define _LOAD_SMALL_INT_2_r23 1209 -#define _LOAD_SMALL_INT_3_r01 1210 -#define _LOAD_SMALL_INT_3_r12 1211 -#define _LOAD_SMALL_INT_3_r23 1212 -#define _LOAD_SPECIAL_r00 1213 -#define _LOAD_SUPER_ATTR_ATTR_r31 1214 -#define _LOAD_SUPER_ATTR_METHOD_r32 1215 -#define _MAKE_CALLARGS_A_TUPLE_r33 1216 -#define _MAKE_CELL_r00 1217 -#define _MAKE_FUNCTION_r11 1218 -#define _MAKE_WARM_r00 1219 -#define _MAKE_WARM_r11 1220 -#define _MAKE_WARM_r22 1221 -#define _MAKE_WARM_r33 1222 -#define _MAP_ADD_r20 1223 -#define _MATCH_CLASS_r31 1224 -#define _MATCH_KEYS_r23 1225 -#define _MATCH_MAPPING_r02 1226 -#define _MATCH_MAPPING_r12 1227 -#define _MATCH_MAPPING_r23 1228 -#define _MATCH_SEQUENCE_r02 1229 -#define _MATCH_SEQUENCE_r12 1230 -#define _MATCH_SEQUENCE_r23 1231 -#define _MAYBE_EXPAND_METHOD_r00 1232 -#define _MAYBE_EXPAND_METHOD_KW_r11 1233 -#define _MONITOR_CALL_r00 1234 -#define _MONITOR_CALL_KW_r11 1235 -#define _MONITOR_JUMP_BACKWARD_r00 1236 -#define _MONITOR_JUMP_BACKWARD_r11 1237 -#define _MONITOR_JUMP_BACKWARD_r22 1238 -#define _MONITOR_JUMP_BACKWARD_r33 1239 -#define _MONITOR_RESUME_r00 1240 -#define _NOP_r00 1241 -#define _NOP_r11 1242 -#define _NOP_r22 1243 -#define _NOP_r33 1244 -#define _POP_CALL_r20 1245 -#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1246 -#define _POP_CALL_ONE_r30 1247 -#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1248 -#define _POP_CALL_TWO_r30 1249 -#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1250 -#define _POP_EXCEPT_r10 1251 -#define _POP_ITER_r20 1252 -#define _POP_JUMP_IF_FALSE_r00 1253 -#define _POP_JUMP_IF_FALSE_r10 1254 -#define _POP_JUMP_IF_FALSE_r21 1255 -#define _POP_JUMP_IF_FALSE_r32 1256 -#define _POP_JUMP_IF_TRUE_r00 1257 -#define _POP_JUMP_IF_TRUE_r10 1258 -#define _POP_JUMP_IF_TRUE_r21 1259 -#define _POP_JUMP_IF_TRUE_r32 1260 -#define _POP_TOP_r10 1261 -#define _POP_TOP_FLOAT_r00 1262 -#define _POP_TOP_FLOAT_r10 1263 -#define _POP_TOP_FLOAT_r21 1264 -#define _POP_TOP_FLOAT_r32 1265 -#define _POP_TOP_INT_r00 1266 -#define _POP_TOP_INT_r10 1267 -#define _POP_TOP_INT_r21 1268 -#define _POP_TOP_INT_r32 1269 -#define _POP_TOP_LOAD_CONST_INLINE_r11 1270 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1271 -#define _POP_TOP_NOP_r00 1272 -#define _POP_TOP_NOP_r10 1273 -#define _POP_TOP_NOP_r21 1274 -#define _POP_TOP_NOP_r32 1275 -#define _POP_TOP_UNICODE_r00 1276 -#define _POP_TOP_UNICODE_r10 1277 -#define _POP_TOP_UNICODE_r21 1278 -#define _POP_TOP_UNICODE_r32 1279 -#define _POP_TWO_r20 1280 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1281 -#define _PUSH_EXC_INFO_r02 1282 -#define _PUSH_EXC_INFO_r12 1283 -#define _PUSH_EXC_INFO_r23 1284 -#define _PUSH_FRAME_r10 1285 -#define _PUSH_NULL_r01 1286 -#define _PUSH_NULL_r12 1287 -#define _PUSH_NULL_r23 1288 -#define _PUSH_NULL_CONDITIONAL_r00 1289 -#define _PY_FRAME_EX_r31 1290 -#define _PY_FRAME_GENERAL_r01 1291 -#define _PY_FRAME_KW_r11 1292 -#define _QUICKEN_RESUME_r00 1293 -#define _QUICKEN_RESUME_r11 1294 -#define _QUICKEN_RESUME_r22 1295 -#define _QUICKEN_RESUME_r33 1296 -#define _REPLACE_WITH_TRUE_r02 1297 -#define _REPLACE_WITH_TRUE_r12 1298 -#define _REPLACE_WITH_TRUE_r23 1299 -#define _RESUME_CHECK_r00 1300 -#define _RESUME_CHECK_r11 1301 -#define _RESUME_CHECK_r22 1302 -#define _RESUME_CHECK_r33 1303 -#define _RETURN_GENERATOR_r01 1304 -#define _RETURN_VALUE_r11 1305 -#define _SAVE_RETURN_OFFSET_r00 1306 -#define _SAVE_RETURN_OFFSET_r11 1307 -#define _SAVE_RETURN_OFFSET_r22 1308 -#define _SAVE_RETURN_OFFSET_r33 1309 -#define _SEND_r22 1310 -#define _SEND_GEN_FRAME_r22 1311 -#define _SETUP_ANNOTATIONS_r00 1312 -#define _SET_ADD_r10 1313 -#define _SET_FUNCTION_ATTRIBUTE_r01 1314 -#define _SET_FUNCTION_ATTRIBUTE_r11 1315 -#define _SET_FUNCTION_ATTRIBUTE_r21 1316 -#define _SET_FUNCTION_ATTRIBUTE_r32 1317 -#define _SET_IP_r00 1318 -#define _SET_IP_r11 1319 -#define _SET_IP_r22 1320 -#define _SET_IP_r33 1321 -#define _SET_UPDATE_r10 1322 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1323 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1324 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1325 -#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1326 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1327 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1328 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1329 -#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1330 -#define _SPILL_OR_RELOAD_r01 1331 -#define _SPILL_OR_RELOAD_r02 1332 -#define _SPILL_OR_RELOAD_r03 1333 -#define _SPILL_OR_RELOAD_r10 1334 -#define _SPILL_OR_RELOAD_r12 1335 -#define _SPILL_OR_RELOAD_r13 1336 -#define _SPILL_OR_RELOAD_r20 1337 -#define _SPILL_OR_RELOAD_r21 1338 -#define _SPILL_OR_RELOAD_r23 1339 -#define _SPILL_OR_RELOAD_r30 1340 -#define _SPILL_OR_RELOAD_r31 1341 -#define _SPILL_OR_RELOAD_r32 1342 -#define _START_EXECUTOR_r00 1343 -#define _STORE_ATTR_r20 1344 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1345 -#define _STORE_ATTR_SLOT_r21 1346 -#define _STORE_ATTR_WITH_HINT_r21 1347 -#define _STORE_DEREF_r10 1348 -#define _STORE_FAST_LOAD_FAST_r11 1349 -#define _STORE_FAST_STORE_FAST_r20 1350 -#define _STORE_GLOBAL_r10 1351 -#define _STORE_NAME_r10 1352 -#define _STORE_SLICE_r30 1353 -#define _STORE_SUBSCR_r30 1354 -#define _STORE_SUBSCR_DICT_r31 1355 -#define _STORE_SUBSCR_LIST_INT_r32 1356 -#define _SWAP_r11 1357 -#define _SWAP_2_r02 1358 -#define _SWAP_2_r12 1359 -#define _SWAP_2_r22 1360 -#define _SWAP_2_r33 1361 -#define _SWAP_3_r03 1362 -#define _SWAP_3_r13 1363 -#define _SWAP_3_r23 1364 -#define _SWAP_3_r33 1365 -#define _SWAP_FAST_r01 1366 -#define _SWAP_FAST_r11 1367 -#define _SWAP_FAST_r22 1368 -#define _SWAP_FAST_r33 1369 -#define _SWAP_FAST_0_r01 1370 -#define _SWAP_FAST_0_r11 1371 -#define _SWAP_FAST_0_r22 1372 -#define _SWAP_FAST_0_r33 1373 -#define _SWAP_FAST_1_r01 1374 -#define _SWAP_FAST_1_r11 1375 -#define _SWAP_FAST_1_r22 1376 -#define _SWAP_FAST_1_r33 1377 -#define _SWAP_FAST_2_r01 1378 -#define _SWAP_FAST_2_r11 1379 -#define _SWAP_FAST_2_r22 1380 -#define _SWAP_FAST_2_r33 1381 -#define _SWAP_FAST_3_r01 1382 -#define _SWAP_FAST_3_r11 1383 -#define _SWAP_FAST_3_r22 1384 -#define _SWAP_FAST_3_r33 1385 -#define _SWAP_FAST_4_r01 1386 -#define _SWAP_FAST_4_r11 1387 -#define _SWAP_FAST_4_r22 1388 -#define _SWAP_FAST_4_r33 1389 -#define _SWAP_FAST_5_r01 1390 -#define _SWAP_FAST_5_r11 1391 -#define _SWAP_FAST_5_r22 1392 -#define _SWAP_FAST_5_r33 1393 -#define _SWAP_FAST_6_r01 1394 -#define _SWAP_FAST_6_r11 1395 -#define _SWAP_FAST_6_r22 1396 -#define _SWAP_FAST_6_r33 1397 -#define _SWAP_FAST_7_r01 1398 -#define _SWAP_FAST_7_r11 1399 -#define _SWAP_FAST_7_r22 1400 -#define _SWAP_FAST_7_r33 1401 -#define _TIER2_RESUME_CHECK_r00 1402 -#define _TIER2_RESUME_CHECK_r11 1403 -#define _TIER2_RESUME_CHECK_r22 1404 -#define _TIER2_RESUME_CHECK_r33 1405 -#define _TO_BOOL_r11 1406 -#define _TO_BOOL_BOOL_r01 1407 -#define _TO_BOOL_BOOL_r11 1408 -#define _TO_BOOL_BOOL_r22 1409 -#define _TO_BOOL_BOOL_r33 1410 -#define _TO_BOOL_INT_r02 1411 -#define _TO_BOOL_INT_r12 1412 -#define _TO_BOOL_INT_r23 1413 -#define _TO_BOOL_LIST_r02 1414 -#define _TO_BOOL_LIST_r12 1415 -#define _TO_BOOL_LIST_r23 1416 -#define _TO_BOOL_NONE_r01 1417 -#define _TO_BOOL_NONE_r11 1418 -#define _TO_BOOL_NONE_r22 1419 -#define _TO_BOOL_NONE_r33 1420 -#define _TO_BOOL_STR_r02 1421 -#define _TO_BOOL_STR_r12 1422 -#define _TO_BOOL_STR_r23 1423 -#define _TRACE_RECORD_r00 1424 -#define _UNARY_INVERT_r12 1425 -#define _UNARY_NEGATIVE_r12 1426 -#define _UNARY_NOT_r01 1427 -#define _UNARY_NOT_r11 1428 -#define _UNARY_NOT_r22 1429 -#define _UNARY_NOT_r33 1430 -#define _UNPACK_EX_r10 1431 -#define _UNPACK_SEQUENCE_r10 1432 -#define _UNPACK_SEQUENCE_LIST_r10 1433 -#define _UNPACK_SEQUENCE_TUPLE_r10 1434 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1435 -#define _WITH_EXCEPT_START_r33 1436 -#define _YIELD_VALUE_r11 1437 -#define MAX_UOP_REGS_ID 1437 +#define _YIELD_VALUE 589 +#define MAX_UOP_ID 589 +#define _BINARY_OP_r23 590 +#define _BINARY_OP_ADD_FLOAT_r03 591 +#define _BINARY_OP_ADD_FLOAT_r13 592 +#define _BINARY_OP_ADD_FLOAT_r23 593 +#define _BINARY_OP_ADD_INT_r03 594 +#define _BINARY_OP_ADD_INT_r13 595 +#define _BINARY_OP_ADD_INT_r23 596 +#define _BINARY_OP_ADD_UNICODE_r03 597 +#define _BINARY_OP_ADD_UNICODE_r13 598 +#define _BINARY_OP_ADD_UNICODE_r23 599 +#define _BINARY_OP_EXTEND_r23 600 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 601 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 602 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 603 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 604 +#define _BINARY_OP_MULTIPLY_INT_r03 605 +#define _BINARY_OP_MULTIPLY_INT_r13 606 +#define _BINARY_OP_MULTIPLY_INT_r23 607 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 608 +#define _BINARY_OP_SUBSCR_DICT_r23 609 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 610 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 611 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 612 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 613 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 614 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r21 615 +#define _BINARY_OP_SUBSCR_STR_INT_r23 616 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 617 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 618 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 619 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 620 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 621 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 622 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 623 +#define _BINARY_OP_SUBTRACT_INT_r03 624 +#define _BINARY_OP_SUBTRACT_INT_r13 625 +#define _BINARY_OP_SUBTRACT_INT_r23 626 +#define _BINARY_SLICE_r31 627 +#define _BUILD_INTERPOLATION_r01 628 +#define _BUILD_LIST_r01 629 +#define _BUILD_MAP_r01 630 +#define _BUILD_SET_r01 631 +#define _BUILD_SLICE_r01 632 +#define _BUILD_STRING_r01 633 +#define _BUILD_TEMPLATE_r21 634 +#define _BUILD_TUPLE_r01 635 +#define _CALL_BUILTIN_CLASS_r01 636 +#define _CALL_BUILTIN_FAST_r01 637 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r01 638 +#define _CALL_BUILTIN_O_r03 639 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 640 +#define _CALL_INTRINSIC_1_r11 641 +#define _CALL_INTRINSIC_2_r21 642 +#define _CALL_ISINSTANCE_r31 643 +#define _CALL_KW_NON_PY_r11 644 +#define _CALL_LEN_r33 645 +#define _CALL_LIST_APPEND_r03 646 +#define _CALL_LIST_APPEND_r13 647 +#define _CALL_LIST_APPEND_r23 648 +#define _CALL_LIST_APPEND_r33 649 +#define _CALL_METHOD_DESCRIPTOR_FAST_r01 650 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 651 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 652 +#define _CALL_METHOD_DESCRIPTOR_O_r03 653 +#define _CALL_NON_PY_GENERAL_r01 654 +#define _CALL_STR_1_r32 655 +#define _CALL_TUPLE_1_r32 656 +#define _CALL_TYPE_1_r02 657 +#define _CALL_TYPE_1_r12 658 +#define _CALL_TYPE_1_r22 659 +#define _CALL_TYPE_1_r32 660 +#define _CHECK_AND_ALLOCATE_OBJECT_r00 661 +#define _CHECK_ATTR_CLASS_r01 662 +#define _CHECK_ATTR_CLASS_r11 663 +#define _CHECK_ATTR_CLASS_r22 664 +#define _CHECK_ATTR_CLASS_r33 665 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 666 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 667 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 668 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 669 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 670 +#define _CHECK_EG_MATCH_r22 671 +#define _CHECK_EXC_MATCH_r22 672 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 673 +#define _CHECK_FUNCTION_VERSION_r00 674 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 675 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 676 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 677 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 678 +#define _CHECK_FUNCTION_VERSION_KW_r11 679 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 680 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 681 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 682 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 683 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 684 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 685 +#define _CHECK_IS_PY_CALLABLE_EX_r03 686 +#define _CHECK_IS_PY_CALLABLE_EX_r13 687 +#define _CHECK_IS_PY_CALLABLE_EX_r23 688 +#define _CHECK_IS_PY_CALLABLE_EX_r33 689 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 690 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 691 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 692 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 693 +#define _CHECK_METHOD_VERSION_r00 694 +#define _CHECK_METHOD_VERSION_KW_r11 695 +#define _CHECK_PEP_523_r00 696 +#define _CHECK_PEP_523_r11 697 +#define _CHECK_PEP_523_r22 698 +#define _CHECK_PEP_523_r33 699 +#define _CHECK_PERIODIC_r00 700 +#define _CHECK_PERIODIC_AT_END_r00 701 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 702 +#define _CHECK_RECURSION_REMAINING_r00 703 +#define _CHECK_RECURSION_REMAINING_r11 704 +#define _CHECK_RECURSION_REMAINING_r22 705 +#define _CHECK_RECURSION_REMAINING_r33 706 +#define _CHECK_STACK_SPACE_r00 707 +#define _CHECK_STACK_SPACE_OPERAND_r00 708 +#define _CHECK_STACK_SPACE_OPERAND_r11 709 +#define _CHECK_STACK_SPACE_OPERAND_r22 710 +#define _CHECK_STACK_SPACE_OPERAND_r33 711 +#define _CHECK_VALIDITY_r00 712 +#define _CHECK_VALIDITY_r11 713 +#define _CHECK_VALIDITY_r22 714 +#define _CHECK_VALIDITY_r33 715 +#define _COLD_DYNAMIC_EXIT_r00 716 +#define _COLD_EXIT_r00 717 +#define _COMPARE_OP_r21 718 +#define _COMPARE_OP_FLOAT_r03 719 +#define _COMPARE_OP_FLOAT_r13 720 +#define _COMPARE_OP_FLOAT_r23 721 +#define _COMPARE_OP_INT_r23 722 +#define _COMPARE_OP_STR_r23 723 +#define _CONTAINS_OP_r23 724 +#define _CONTAINS_OP_DICT_r23 725 +#define _CONTAINS_OP_SET_r23 726 +#define _CONVERT_VALUE_r11 727 +#define _COPY_r01 728 +#define _COPY_1_r02 729 +#define _COPY_1_r12 730 +#define _COPY_1_r23 731 +#define _COPY_2_r03 732 +#define _COPY_2_r13 733 +#define _COPY_2_r23 734 +#define _COPY_3_r03 735 +#define _COPY_3_r13 736 +#define _COPY_3_r23 737 +#define _COPY_3_r33 738 +#define _COPY_FREE_VARS_r00 739 +#define _COPY_FREE_VARS_r11 740 +#define _COPY_FREE_VARS_r22 741 +#define _COPY_FREE_VARS_r33 742 +#define _CREATE_INIT_FRAME_r01 743 +#define _DELETE_ATTR_r10 744 +#define _DELETE_DEREF_r00 745 +#define _DELETE_FAST_r00 746 +#define _DELETE_GLOBAL_r00 747 +#define _DELETE_NAME_r00 748 +#define _DELETE_SUBSCR_r20 749 +#define _DEOPT_r00 750 +#define _DEOPT_r10 751 +#define _DEOPT_r20 752 +#define _DEOPT_r30 753 +#define _DICT_MERGE_r10 754 +#define _DICT_UPDATE_r10 755 +#define _DO_CALL_r01 756 +#define _DO_CALL_FUNCTION_EX_r31 757 +#define _DO_CALL_KW_r11 758 +#define _DYNAMIC_EXIT_r00 759 +#define _DYNAMIC_EXIT_r10 760 +#define _DYNAMIC_EXIT_r20 761 +#define _DYNAMIC_EXIT_r30 762 +#define _END_FOR_r10 763 +#define _END_SEND_r21 764 +#define _ERROR_POP_N_r00 765 +#define _EXIT_INIT_CHECK_r10 766 +#define _EXIT_TRACE_r00 767 +#define _EXIT_TRACE_r10 768 +#define _EXIT_TRACE_r20 769 +#define _EXIT_TRACE_r30 770 +#define _EXPAND_METHOD_r00 771 +#define _EXPAND_METHOD_KW_r11 772 +#define _FATAL_ERROR_r00 773 +#define _FATAL_ERROR_r11 774 +#define _FATAL_ERROR_r22 775 +#define _FATAL_ERROR_r33 776 +#define _FORMAT_SIMPLE_r11 777 +#define _FORMAT_WITH_SPEC_r21 778 +#define _FOR_ITER_r23 779 +#define _FOR_ITER_GEN_FRAME_r03 780 +#define _FOR_ITER_GEN_FRAME_r13 781 +#define _FOR_ITER_GEN_FRAME_r23 782 +#define _FOR_ITER_TIER_TWO_r23 783 +#define _GET_AITER_r11 784 +#define _GET_ANEXT_r12 785 +#define _GET_AWAITABLE_r11 786 +#define _GET_ITER_r12 787 +#define _GET_LEN_r12 788 +#define _GET_YIELD_FROM_ITER_r11 789 +#define _GUARD_BINARY_OP_EXTEND_r22 790 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 791 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 792 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 793 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 794 +#define _GUARD_BIT_IS_SET_POP_r00 795 +#define _GUARD_BIT_IS_SET_POP_r10 796 +#define _GUARD_BIT_IS_SET_POP_r21 797 +#define _GUARD_BIT_IS_SET_POP_r32 798 +#define _GUARD_BIT_IS_SET_POP_4_r00 799 +#define _GUARD_BIT_IS_SET_POP_4_r10 800 +#define _GUARD_BIT_IS_SET_POP_4_r21 801 +#define _GUARD_BIT_IS_SET_POP_4_r32 802 +#define _GUARD_BIT_IS_SET_POP_5_r00 803 +#define _GUARD_BIT_IS_SET_POP_5_r10 804 +#define _GUARD_BIT_IS_SET_POP_5_r21 805 +#define _GUARD_BIT_IS_SET_POP_5_r32 806 +#define _GUARD_BIT_IS_SET_POP_6_r00 807 +#define _GUARD_BIT_IS_SET_POP_6_r10 808 +#define _GUARD_BIT_IS_SET_POP_6_r21 809 +#define _GUARD_BIT_IS_SET_POP_6_r32 810 +#define _GUARD_BIT_IS_SET_POP_7_r00 811 +#define _GUARD_BIT_IS_SET_POP_7_r10 812 +#define _GUARD_BIT_IS_SET_POP_7_r21 813 +#define _GUARD_BIT_IS_SET_POP_7_r32 814 +#define _GUARD_BIT_IS_UNSET_POP_r00 815 +#define _GUARD_BIT_IS_UNSET_POP_r10 816 +#define _GUARD_BIT_IS_UNSET_POP_r21 817 +#define _GUARD_BIT_IS_UNSET_POP_r32 818 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 819 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 820 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 821 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 822 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 823 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 824 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 825 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 826 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 827 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 828 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 829 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 830 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 831 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 832 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 833 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 834 +#define _GUARD_CALLABLE_ISINSTANCE_r03 835 +#define _GUARD_CALLABLE_ISINSTANCE_r13 836 +#define _GUARD_CALLABLE_ISINSTANCE_r23 837 +#define _GUARD_CALLABLE_ISINSTANCE_r33 838 +#define _GUARD_CALLABLE_LEN_r03 839 +#define _GUARD_CALLABLE_LEN_r13 840 +#define _GUARD_CALLABLE_LEN_r23 841 +#define _GUARD_CALLABLE_LEN_r33 842 +#define _GUARD_CALLABLE_LIST_APPEND_r03 843 +#define _GUARD_CALLABLE_LIST_APPEND_r13 844 +#define _GUARD_CALLABLE_LIST_APPEND_r23 845 +#define _GUARD_CALLABLE_LIST_APPEND_r33 846 +#define _GUARD_CALLABLE_STR_1_r03 847 +#define _GUARD_CALLABLE_STR_1_r13 848 +#define _GUARD_CALLABLE_STR_1_r23 849 +#define _GUARD_CALLABLE_STR_1_r33 850 +#define _GUARD_CALLABLE_TUPLE_1_r03 851 +#define _GUARD_CALLABLE_TUPLE_1_r13 852 +#define _GUARD_CALLABLE_TUPLE_1_r23 853 +#define _GUARD_CALLABLE_TUPLE_1_r33 854 +#define _GUARD_CALLABLE_TYPE_1_r03 855 +#define _GUARD_CALLABLE_TYPE_1_r13 856 +#define _GUARD_CALLABLE_TYPE_1_r23 857 +#define _GUARD_CALLABLE_TYPE_1_r33 858 +#define _GUARD_DORV_NO_DICT_r01 859 +#define _GUARD_DORV_NO_DICT_r11 860 +#define _GUARD_DORV_NO_DICT_r22 861 +#define _GUARD_DORV_NO_DICT_r33 862 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 863 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 864 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 865 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 866 +#define _GUARD_GLOBALS_VERSION_r00 867 +#define _GUARD_GLOBALS_VERSION_r11 868 +#define _GUARD_GLOBALS_VERSION_r22 869 +#define _GUARD_GLOBALS_VERSION_r33 870 +#define _GUARD_IP_RETURN_GENERATOR_r00 871 +#define _GUARD_IP_RETURN_GENERATOR_r11 872 +#define _GUARD_IP_RETURN_GENERATOR_r22 873 +#define _GUARD_IP_RETURN_GENERATOR_r33 874 +#define _GUARD_IP_RETURN_VALUE_r00 875 +#define _GUARD_IP_RETURN_VALUE_r11 876 +#define _GUARD_IP_RETURN_VALUE_r22 877 +#define _GUARD_IP_RETURN_VALUE_r33 878 +#define _GUARD_IP_YIELD_VALUE_r00 879 +#define _GUARD_IP_YIELD_VALUE_r11 880 +#define _GUARD_IP_YIELD_VALUE_r22 881 +#define _GUARD_IP_YIELD_VALUE_r33 882 +#define _GUARD_IP__PUSH_FRAME_r00 883 +#define _GUARD_IP__PUSH_FRAME_r11 884 +#define _GUARD_IP__PUSH_FRAME_r22 885 +#define _GUARD_IP__PUSH_FRAME_r33 886 +#define _GUARD_IS_FALSE_POP_r00 887 +#define _GUARD_IS_FALSE_POP_r10 888 +#define _GUARD_IS_FALSE_POP_r21 889 +#define _GUARD_IS_FALSE_POP_r32 890 +#define _GUARD_IS_NONE_POP_r00 891 +#define _GUARD_IS_NONE_POP_r10 892 +#define _GUARD_IS_NONE_POP_r21 893 +#define _GUARD_IS_NONE_POP_r32 894 +#define _GUARD_IS_NOT_NONE_POP_r10 895 +#define _GUARD_IS_TRUE_POP_r00 896 +#define _GUARD_IS_TRUE_POP_r10 897 +#define _GUARD_IS_TRUE_POP_r21 898 +#define _GUARD_IS_TRUE_POP_r32 899 +#define _GUARD_KEYS_VERSION_r01 900 +#define _GUARD_KEYS_VERSION_r11 901 +#define _GUARD_KEYS_VERSION_r22 902 +#define _GUARD_KEYS_VERSION_r33 903 +#define _GUARD_NOS_COMPACT_ASCII_r02 904 +#define _GUARD_NOS_COMPACT_ASCII_r12 905 +#define _GUARD_NOS_COMPACT_ASCII_r22 906 +#define _GUARD_NOS_COMPACT_ASCII_r33 907 +#define _GUARD_NOS_DICT_r02 908 +#define _GUARD_NOS_DICT_r12 909 +#define _GUARD_NOS_DICT_r22 910 +#define _GUARD_NOS_DICT_r33 911 +#define _GUARD_NOS_FLOAT_r02 912 +#define _GUARD_NOS_FLOAT_r12 913 +#define _GUARD_NOS_FLOAT_r22 914 +#define _GUARD_NOS_FLOAT_r33 915 +#define _GUARD_NOS_INT_r02 916 +#define _GUARD_NOS_INT_r12 917 +#define _GUARD_NOS_INT_r22 918 +#define _GUARD_NOS_INT_r33 919 +#define _GUARD_NOS_LIST_r02 920 +#define _GUARD_NOS_LIST_r12 921 +#define _GUARD_NOS_LIST_r22 922 +#define _GUARD_NOS_LIST_r33 923 +#define _GUARD_NOS_NOT_NULL_r02 924 +#define _GUARD_NOS_NOT_NULL_r12 925 +#define _GUARD_NOS_NOT_NULL_r22 926 +#define _GUARD_NOS_NOT_NULL_r33 927 +#define _GUARD_NOS_NULL_r02 928 +#define _GUARD_NOS_NULL_r12 929 +#define _GUARD_NOS_NULL_r22 930 +#define _GUARD_NOS_NULL_r33 931 +#define _GUARD_NOS_OVERFLOWED_r02 932 +#define _GUARD_NOS_OVERFLOWED_r12 933 +#define _GUARD_NOS_OVERFLOWED_r22 934 +#define _GUARD_NOS_OVERFLOWED_r33 935 +#define _GUARD_NOS_TUPLE_r02 936 +#define _GUARD_NOS_TUPLE_r12 937 +#define _GUARD_NOS_TUPLE_r22 938 +#define _GUARD_NOS_TUPLE_r33 939 +#define _GUARD_NOS_UNICODE_r02 940 +#define _GUARD_NOS_UNICODE_r12 941 +#define _GUARD_NOS_UNICODE_r22 942 +#define _GUARD_NOS_UNICODE_r33 943 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 944 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 945 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 946 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 947 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 948 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 949 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 950 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 951 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 952 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 953 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 954 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 955 +#define _GUARD_THIRD_NULL_r03 956 +#define _GUARD_THIRD_NULL_r13 957 +#define _GUARD_THIRD_NULL_r23 958 +#define _GUARD_THIRD_NULL_r33 959 +#define _GUARD_TOS_ANY_SET_r01 960 +#define _GUARD_TOS_ANY_SET_r11 961 +#define _GUARD_TOS_ANY_SET_r22 962 +#define _GUARD_TOS_ANY_SET_r33 963 +#define _GUARD_TOS_DICT_r01 964 +#define _GUARD_TOS_DICT_r11 965 +#define _GUARD_TOS_DICT_r22 966 +#define _GUARD_TOS_DICT_r33 967 +#define _GUARD_TOS_FLOAT_r01 968 +#define _GUARD_TOS_FLOAT_r11 969 +#define _GUARD_TOS_FLOAT_r22 970 +#define _GUARD_TOS_FLOAT_r33 971 +#define _GUARD_TOS_INT_r01 972 +#define _GUARD_TOS_INT_r11 973 +#define _GUARD_TOS_INT_r22 974 +#define _GUARD_TOS_INT_r33 975 +#define _GUARD_TOS_LIST_r01 976 +#define _GUARD_TOS_LIST_r11 977 +#define _GUARD_TOS_LIST_r22 978 +#define _GUARD_TOS_LIST_r33 979 +#define _GUARD_TOS_OVERFLOWED_r01 980 +#define _GUARD_TOS_OVERFLOWED_r11 981 +#define _GUARD_TOS_OVERFLOWED_r22 982 +#define _GUARD_TOS_OVERFLOWED_r33 983 +#define _GUARD_TOS_SLICE_r01 984 +#define _GUARD_TOS_SLICE_r11 985 +#define _GUARD_TOS_SLICE_r22 986 +#define _GUARD_TOS_SLICE_r33 987 +#define _GUARD_TOS_TUPLE_r01 988 +#define _GUARD_TOS_TUPLE_r11 989 +#define _GUARD_TOS_TUPLE_r22 990 +#define _GUARD_TOS_TUPLE_r33 991 +#define _GUARD_TOS_UNICODE_r01 992 +#define _GUARD_TOS_UNICODE_r11 993 +#define _GUARD_TOS_UNICODE_r22 994 +#define _GUARD_TOS_UNICODE_r33 995 +#define _GUARD_TYPE_VERSION_r01 996 +#define _GUARD_TYPE_VERSION_r11 997 +#define _GUARD_TYPE_VERSION_r22 998 +#define _GUARD_TYPE_VERSION_r33 999 +#define _GUARD_TYPE_VERSION_AND_LOCK_r01 1000 +#define _GUARD_TYPE_VERSION_AND_LOCK_r11 1001 +#define _GUARD_TYPE_VERSION_AND_LOCK_r22 1002 +#define _GUARD_TYPE_VERSION_AND_LOCK_r33 1003 +#define _HANDLE_PENDING_AND_DEOPT_r00 1004 +#define _HANDLE_PENDING_AND_DEOPT_r10 1005 +#define _HANDLE_PENDING_AND_DEOPT_r20 1006 +#define _HANDLE_PENDING_AND_DEOPT_r30 1007 +#define _IMPORT_FROM_r12 1008 +#define _IMPORT_NAME_r21 1009 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1010 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1011 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1012 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1013 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1014 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1015 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1016 +#define _INSERT_1_LOAD_CONST_INLINE_r02 1017 +#define _INSERT_1_LOAD_CONST_INLINE_r12 1018 +#define _INSERT_1_LOAD_CONST_INLINE_r23 1019 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r02 1020 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r12 1021 +#define _INSERT_1_LOAD_CONST_INLINE_BORROW_r23 1022 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r03 1023 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r13 1024 +#define _INSERT_2_LOAD_CONST_INLINE_BORROW_r23 1025 +#define _INSERT_NULL_r10 1026 +#define _INSTRUMENTED_FOR_ITER_r23 1027 +#define _INSTRUMENTED_INSTRUCTION_r00 1028 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1029 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1030 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1031 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1032 +#define _INSTRUMENTED_LINE_r00 1033 +#define _INSTRUMENTED_NOT_TAKEN_r00 1034 +#define _INSTRUMENTED_NOT_TAKEN_r11 1035 +#define _INSTRUMENTED_NOT_TAKEN_r22 1036 +#define _INSTRUMENTED_NOT_TAKEN_r33 1037 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1038 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1039 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1040 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1041 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1042 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1043 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1044 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1045 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1046 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1047 +#define _IS_NONE_r11 1048 +#define _IS_OP_r03 1049 +#define _IS_OP_r13 1050 +#define _IS_OP_r23 1051 +#define _ITER_CHECK_LIST_r02 1052 +#define _ITER_CHECK_LIST_r12 1053 +#define _ITER_CHECK_LIST_r22 1054 +#define _ITER_CHECK_LIST_r33 1055 +#define _ITER_CHECK_RANGE_r02 1056 +#define _ITER_CHECK_RANGE_r12 1057 +#define _ITER_CHECK_RANGE_r22 1058 +#define _ITER_CHECK_RANGE_r33 1059 +#define _ITER_CHECK_TUPLE_r02 1060 +#define _ITER_CHECK_TUPLE_r12 1061 +#define _ITER_CHECK_TUPLE_r22 1062 +#define _ITER_CHECK_TUPLE_r33 1063 +#define _ITER_JUMP_LIST_r02 1064 +#define _ITER_JUMP_LIST_r12 1065 +#define _ITER_JUMP_LIST_r22 1066 +#define _ITER_JUMP_LIST_r33 1067 +#define _ITER_JUMP_RANGE_r02 1068 +#define _ITER_JUMP_RANGE_r12 1069 +#define _ITER_JUMP_RANGE_r22 1070 +#define _ITER_JUMP_RANGE_r33 1071 +#define _ITER_JUMP_TUPLE_r02 1072 +#define _ITER_JUMP_TUPLE_r12 1073 +#define _ITER_JUMP_TUPLE_r22 1074 +#define _ITER_JUMP_TUPLE_r33 1075 +#define _ITER_NEXT_LIST_r23 1076 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1077 +#define _ITER_NEXT_RANGE_r03 1078 +#define _ITER_NEXT_RANGE_r13 1079 +#define _ITER_NEXT_RANGE_r23 1080 +#define _ITER_NEXT_TUPLE_r03 1081 +#define _ITER_NEXT_TUPLE_r13 1082 +#define _ITER_NEXT_TUPLE_r23 1083 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1084 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1085 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1086 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1087 +#define _JUMP_TO_TOP_r00 1088 +#define _LIST_APPEND_r10 1089 +#define _LIST_EXTEND_r10 1090 +#define _LOAD_ATTR_r10 1091 +#define _LOAD_ATTR_CLASS_r11 1092 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_r11 1093 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1094 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1095 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1096 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1097 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1098 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1099 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1100 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1101 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1102 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1103 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1104 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1105 +#define _LOAD_ATTR_MODULE_r12 1106 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1107 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1108 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1109 +#define _LOAD_ATTR_SLOT_r02 1110 +#define _LOAD_ATTR_SLOT_r12 1111 +#define _LOAD_ATTR_SLOT_r23 1112 +#define _LOAD_ATTR_WITH_HINT_r12 1113 +#define _LOAD_BUILD_CLASS_r01 1114 +#define _LOAD_BYTECODE_r00 1115 +#define _LOAD_COMMON_CONSTANT_r01 1116 +#define _LOAD_COMMON_CONSTANT_r12 1117 +#define _LOAD_COMMON_CONSTANT_r23 1118 +#define _LOAD_CONST_r01 1119 +#define _LOAD_CONST_r12 1120 +#define _LOAD_CONST_r23 1121 +#define _LOAD_CONST_INLINE_r01 1122 +#define _LOAD_CONST_INLINE_r12 1123 +#define _LOAD_CONST_INLINE_r23 1124 +#define _LOAD_CONST_INLINE_BORROW_r01 1125 +#define _LOAD_CONST_INLINE_BORROW_r12 1126 +#define _LOAD_CONST_INLINE_BORROW_r23 1127 +#define _LOAD_CONST_UNDER_INLINE_r02 1128 +#define _LOAD_CONST_UNDER_INLINE_r12 1129 +#define _LOAD_CONST_UNDER_INLINE_r23 1130 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r02 1131 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r12 1132 +#define _LOAD_CONST_UNDER_INLINE_BORROW_r23 1133 +#define _LOAD_DEREF_r01 1134 +#define _LOAD_FAST_r01 1135 +#define _LOAD_FAST_r12 1136 +#define _LOAD_FAST_r23 1137 +#define _LOAD_FAST_0_r01 1138 +#define _LOAD_FAST_0_r12 1139 +#define _LOAD_FAST_0_r23 1140 +#define _LOAD_FAST_1_r01 1141 +#define _LOAD_FAST_1_r12 1142 +#define _LOAD_FAST_1_r23 1143 +#define _LOAD_FAST_2_r01 1144 +#define _LOAD_FAST_2_r12 1145 +#define _LOAD_FAST_2_r23 1146 +#define _LOAD_FAST_3_r01 1147 +#define _LOAD_FAST_3_r12 1148 +#define _LOAD_FAST_3_r23 1149 +#define _LOAD_FAST_4_r01 1150 +#define _LOAD_FAST_4_r12 1151 +#define _LOAD_FAST_4_r23 1152 +#define _LOAD_FAST_5_r01 1153 +#define _LOAD_FAST_5_r12 1154 +#define _LOAD_FAST_5_r23 1155 +#define _LOAD_FAST_6_r01 1156 +#define _LOAD_FAST_6_r12 1157 +#define _LOAD_FAST_6_r23 1158 +#define _LOAD_FAST_7_r01 1159 +#define _LOAD_FAST_7_r12 1160 +#define _LOAD_FAST_7_r23 1161 +#define _LOAD_FAST_AND_CLEAR_r01 1162 +#define _LOAD_FAST_AND_CLEAR_r12 1163 +#define _LOAD_FAST_AND_CLEAR_r23 1164 +#define _LOAD_FAST_BORROW_r01 1165 +#define _LOAD_FAST_BORROW_r12 1166 +#define _LOAD_FAST_BORROW_r23 1167 +#define _LOAD_FAST_BORROW_0_r01 1168 +#define _LOAD_FAST_BORROW_0_r12 1169 +#define _LOAD_FAST_BORROW_0_r23 1170 +#define _LOAD_FAST_BORROW_1_r01 1171 +#define _LOAD_FAST_BORROW_1_r12 1172 +#define _LOAD_FAST_BORROW_1_r23 1173 +#define _LOAD_FAST_BORROW_2_r01 1174 +#define _LOAD_FAST_BORROW_2_r12 1175 +#define _LOAD_FAST_BORROW_2_r23 1176 +#define _LOAD_FAST_BORROW_3_r01 1177 +#define _LOAD_FAST_BORROW_3_r12 1178 +#define _LOAD_FAST_BORROW_3_r23 1179 +#define _LOAD_FAST_BORROW_4_r01 1180 +#define _LOAD_FAST_BORROW_4_r12 1181 +#define _LOAD_FAST_BORROW_4_r23 1182 +#define _LOAD_FAST_BORROW_5_r01 1183 +#define _LOAD_FAST_BORROW_5_r12 1184 +#define _LOAD_FAST_BORROW_5_r23 1185 +#define _LOAD_FAST_BORROW_6_r01 1186 +#define _LOAD_FAST_BORROW_6_r12 1187 +#define _LOAD_FAST_BORROW_6_r23 1188 +#define _LOAD_FAST_BORROW_7_r01 1189 +#define _LOAD_FAST_BORROW_7_r12 1190 +#define _LOAD_FAST_BORROW_7_r23 1191 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1192 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1193 +#define _LOAD_FAST_CHECK_r01 1194 +#define _LOAD_FAST_CHECK_r12 1195 +#define _LOAD_FAST_CHECK_r23 1196 +#define _LOAD_FAST_LOAD_FAST_r02 1197 +#define _LOAD_FAST_LOAD_FAST_r13 1198 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1199 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1200 +#define _LOAD_GLOBAL_r00 1201 +#define _LOAD_GLOBAL_BUILTINS_r01 1202 +#define _LOAD_GLOBAL_MODULE_r01 1203 +#define _LOAD_LOCALS_r01 1204 +#define _LOAD_LOCALS_r12 1205 +#define _LOAD_LOCALS_r23 1206 +#define _LOAD_NAME_r01 1207 +#define _LOAD_SMALL_INT_r01 1208 +#define _LOAD_SMALL_INT_r12 1209 +#define _LOAD_SMALL_INT_r23 1210 +#define _LOAD_SMALL_INT_0_r01 1211 +#define _LOAD_SMALL_INT_0_r12 1212 +#define _LOAD_SMALL_INT_0_r23 1213 +#define _LOAD_SMALL_INT_1_r01 1214 +#define _LOAD_SMALL_INT_1_r12 1215 +#define _LOAD_SMALL_INT_1_r23 1216 +#define _LOAD_SMALL_INT_2_r01 1217 +#define _LOAD_SMALL_INT_2_r12 1218 +#define _LOAD_SMALL_INT_2_r23 1219 +#define _LOAD_SMALL_INT_3_r01 1220 +#define _LOAD_SMALL_INT_3_r12 1221 +#define _LOAD_SMALL_INT_3_r23 1222 +#define _LOAD_SPECIAL_r00 1223 +#define _LOAD_SUPER_ATTR_ATTR_r31 1224 +#define _LOAD_SUPER_ATTR_METHOD_r32 1225 +#define _MAKE_CALLARGS_A_TUPLE_r33 1226 +#define _MAKE_CELL_r00 1227 +#define _MAKE_FUNCTION_r11 1228 +#define _MAKE_WARM_r00 1229 +#define _MAKE_WARM_r11 1230 +#define _MAKE_WARM_r22 1231 +#define _MAKE_WARM_r33 1232 +#define _MAP_ADD_r20 1233 +#define _MATCH_CLASS_r31 1234 +#define _MATCH_KEYS_r23 1235 +#define _MATCH_MAPPING_r02 1236 +#define _MATCH_MAPPING_r12 1237 +#define _MATCH_MAPPING_r23 1238 +#define _MATCH_SEQUENCE_r02 1239 +#define _MATCH_SEQUENCE_r12 1240 +#define _MATCH_SEQUENCE_r23 1241 +#define _MAYBE_EXPAND_METHOD_r00 1242 +#define _MAYBE_EXPAND_METHOD_KW_r11 1243 +#define _MONITOR_CALL_r00 1244 +#define _MONITOR_CALL_KW_r11 1245 +#define _MONITOR_JUMP_BACKWARD_r00 1246 +#define _MONITOR_JUMP_BACKWARD_r11 1247 +#define _MONITOR_JUMP_BACKWARD_r22 1248 +#define _MONITOR_JUMP_BACKWARD_r33 1249 +#define _MONITOR_RESUME_r00 1250 +#define _NOP_r00 1251 +#define _NOP_r11 1252 +#define _NOP_r22 1253 +#define _NOP_r33 1254 +#define _POP_CALL_r20 1255 +#define _POP_CALL_LOAD_CONST_INLINE_BORROW_r21 1256 +#define _POP_CALL_ONE_r30 1257 +#define _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 1258 +#define _POP_CALL_TWO_r30 1259 +#define _POP_CALL_TWO_LOAD_CONST_INLINE_BORROW_r31 1260 +#define _POP_EXCEPT_r10 1261 +#define _POP_ITER_r20 1262 +#define _POP_JUMP_IF_FALSE_r00 1263 +#define _POP_JUMP_IF_FALSE_r10 1264 +#define _POP_JUMP_IF_FALSE_r21 1265 +#define _POP_JUMP_IF_FALSE_r32 1266 +#define _POP_JUMP_IF_TRUE_r00 1267 +#define _POP_JUMP_IF_TRUE_r10 1268 +#define _POP_JUMP_IF_TRUE_r21 1269 +#define _POP_JUMP_IF_TRUE_r32 1270 +#define _POP_TOP_r10 1271 +#define _POP_TOP_FLOAT_r00 1272 +#define _POP_TOP_FLOAT_r10 1273 +#define _POP_TOP_FLOAT_r21 1274 +#define _POP_TOP_FLOAT_r32 1275 +#define _POP_TOP_INT_r00 1276 +#define _POP_TOP_INT_r10 1277 +#define _POP_TOP_INT_r21 1278 +#define _POP_TOP_INT_r32 1279 +#define _POP_TOP_LOAD_CONST_INLINE_r11 1280 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW_r11 1281 +#define _POP_TOP_NOP_r00 1282 +#define _POP_TOP_NOP_r10 1283 +#define _POP_TOP_NOP_r21 1284 +#define _POP_TOP_NOP_r32 1285 +#define _POP_TOP_UNICODE_r00 1286 +#define _POP_TOP_UNICODE_r10 1287 +#define _POP_TOP_UNICODE_r21 1288 +#define _POP_TOP_UNICODE_r32 1289 +#define _POP_TWO_r20 1290 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW_r21 1291 +#define _PUSH_EXC_INFO_r02 1292 +#define _PUSH_EXC_INFO_r12 1293 +#define _PUSH_EXC_INFO_r23 1294 +#define _PUSH_FRAME_r10 1295 +#define _PUSH_NULL_r01 1296 +#define _PUSH_NULL_r12 1297 +#define _PUSH_NULL_r23 1298 +#define _PUSH_NULL_CONDITIONAL_r00 1299 +#define _PY_FRAME_EX_r31 1300 +#define _PY_FRAME_GENERAL_r01 1301 +#define _PY_FRAME_KW_r11 1302 +#define _QUICKEN_RESUME_r00 1303 +#define _QUICKEN_RESUME_r11 1304 +#define _QUICKEN_RESUME_r22 1305 +#define _QUICKEN_RESUME_r33 1306 +#define _REPLACE_WITH_TRUE_r02 1307 +#define _REPLACE_WITH_TRUE_r12 1308 +#define _REPLACE_WITH_TRUE_r23 1309 +#define _RESUME_CHECK_r00 1310 +#define _RESUME_CHECK_r11 1311 +#define _RESUME_CHECK_r22 1312 +#define _RESUME_CHECK_r33 1313 +#define _RETURN_GENERATOR_r01 1314 +#define _RETURN_VALUE_r11 1315 +#define _SAVE_RETURN_OFFSET_r00 1316 +#define _SAVE_RETURN_OFFSET_r11 1317 +#define _SAVE_RETURN_OFFSET_r22 1318 +#define _SAVE_RETURN_OFFSET_r33 1319 +#define _SEND_r22 1320 +#define _SEND_GEN_FRAME_r22 1321 +#define _SETUP_ANNOTATIONS_r00 1322 +#define _SET_ADD_r10 1323 +#define _SET_FUNCTION_ATTRIBUTE_r01 1324 +#define _SET_FUNCTION_ATTRIBUTE_r11 1325 +#define _SET_FUNCTION_ATTRIBUTE_r21 1326 +#define _SET_FUNCTION_ATTRIBUTE_r32 1327 +#define _SET_IP_r00 1328 +#define _SET_IP_r11 1329 +#define _SET_IP_r22 1330 +#define _SET_IP_r33 1331 +#define _SET_UPDATE_r10 1332 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r02 1333 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r12 1334 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r22 1335 +#define _SHUFFLE_2_LOAD_CONST_INLINE_BORROW_r32 1336 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r03 1337 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r13 1338 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r23 1339 +#define _SHUFFLE_3_LOAD_CONST_INLINE_BORROW_r33 1340 +#define _SPILL_OR_RELOAD_r01 1341 +#define _SPILL_OR_RELOAD_r02 1342 +#define _SPILL_OR_RELOAD_r03 1343 +#define _SPILL_OR_RELOAD_r10 1344 +#define _SPILL_OR_RELOAD_r12 1345 +#define _SPILL_OR_RELOAD_r13 1346 +#define _SPILL_OR_RELOAD_r20 1347 +#define _SPILL_OR_RELOAD_r21 1348 +#define _SPILL_OR_RELOAD_r23 1349 +#define _SPILL_OR_RELOAD_r30 1350 +#define _SPILL_OR_RELOAD_r31 1351 +#define _SPILL_OR_RELOAD_r32 1352 +#define _START_EXECUTOR_r00 1353 +#define _STORE_ATTR_r20 1354 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1355 +#define _STORE_ATTR_SLOT_r21 1356 +#define _STORE_ATTR_WITH_HINT_r21 1357 +#define _STORE_DEREF_r10 1358 +#define _STORE_FAST_LOAD_FAST_r11 1359 +#define _STORE_FAST_STORE_FAST_r20 1360 +#define _STORE_GLOBAL_r10 1361 +#define _STORE_NAME_r10 1362 +#define _STORE_SLICE_r30 1363 +#define _STORE_SUBSCR_r30 1364 +#define _STORE_SUBSCR_DICT_r31 1365 +#define _STORE_SUBSCR_LIST_INT_r32 1366 +#define _SWAP_r11 1367 +#define _SWAP_2_r02 1368 +#define _SWAP_2_r12 1369 +#define _SWAP_2_r22 1370 +#define _SWAP_2_r33 1371 +#define _SWAP_3_r03 1372 +#define _SWAP_3_r13 1373 +#define _SWAP_3_r23 1374 +#define _SWAP_3_r33 1375 +#define _SWAP_FAST_r01 1376 +#define _SWAP_FAST_r11 1377 +#define _SWAP_FAST_r22 1378 +#define _SWAP_FAST_r33 1379 +#define _SWAP_FAST_0_r01 1380 +#define _SWAP_FAST_0_r11 1381 +#define _SWAP_FAST_0_r22 1382 +#define _SWAP_FAST_0_r33 1383 +#define _SWAP_FAST_1_r01 1384 +#define _SWAP_FAST_1_r11 1385 +#define _SWAP_FAST_1_r22 1386 +#define _SWAP_FAST_1_r33 1387 +#define _SWAP_FAST_2_r01 1388 +#define _SWAP_FAST_2_r11 1389 +#define _SWAP_FAST_2_r22 1390 +#define _SWAP_FAST_2_r33 1391 +#define _SWAP_FAST_3_r01 1392 +#define _SWAP_FAST_3_r11 1393 +#define _SWAP_FAST_3_r22 1394 +#define _SWAP_FAST_3_r33 1395 +#define _SWAP_FAST_4_r01 1396 +#define _SWAP_FAST_4_r11 1397 +#define _SWAP_FAST_4_r22 1398 +#define _SWAP_FAST_4_r33 1399 +#define _SWAP_FAST_5_r01 1400 +#define _SWAP_FAST_5_r11 1401 +#define _SWAP_FAST_5_r22 1402 +#define _SWAP_FAST_5_r33 1403 +#define _SWAP_FAST_6_r01 1404 +#define _SWAP_FAST_6_r11 1405 +#define _SWAP_FAST_6_r22 1406 +#define _SWAP_FAST_6_r33 1407 +#define _SWAP_FAST_7_r01 1408 +#define _SWAP_FAST_7_r11 1409 +#define _SWAP_FAST_7_r22 1410 +#define _SWAP_FAST_7_r33 1411 +#define _TIER2_RESUME_CHECK_r00 1412 +#define _TIER2_RESUME_CHECK_r11 1413 +#define _TIER2_RESUME_CHECK_r22 1414 +#define _TIER2_RESUME_CHECK_r33 1415 +#define _TO_BOOL_r11 1416 +#define _TO_BOOL_BOOL_r01 1417 +#define _TO_BOOL_BOOL_r11 1418 +#define _TO_BOOL_BOOL_r22 1419 +#define _TO_BOOL_BOOL_r33 1420 +#define _TO_BOOL_INT_r02 1421 +#define _TO_BOOL_INT_r12 1422 +#define _TO_BOOL_INT_r23 1423 +#define _TO_BOOL_LIST_r02 1424 +#define _TO_BOOL_LIST_r12 1425 +#define _TO_BOOL_LIST_r23 1426 +#define _TO_BOOL_NONE_r01 1427 +#define _TO_BOOL_NONE_r11 1428 +#define _TO_BOOL_NONE_r22 1429 +#define _TO_BOOL_NONE_r33 1430 +#define _TO_BOOL_STR_r02 1431 +#define _TO_BOOL_STR_r12 1432 +#define _TO_BOOL_STR_r23 1433 +#define _TRACE_RECORD_r00 1434 +#define _UNARY_INVERT_r12 1435 +#define _UNARY_NEGATIVE_r12 1436 +#define _UNARY_NOT_r01 1437 +#define _UNARY_NOT_r11 1438 +#define _UNARY_NOT_r22 1439 +#define _UNARY_NOT_r33 1440 +#define _UNPACK_EX_r10 1441 +#define _UNPACK_SEQUENCE_r10 1442 +#define _UNPACK_SEQUENCE_LIST_r10 1443 +#define _UNPACK_SEQUENCE_TUPLE_r10 1444 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1445 +#define _WITH_EXCEPT_START_r33 1446 +#define _YIELD_VALUE_r11 1447 +#define MAX_UOP_REGS_ID 1447 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 07c4f0aeb4a..85f2948ece4 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -374,6 +374,13 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GUARD_IP_YIELD_VALUE] = HAS_EXIT_FLAG, [_GUARD_IP_RETURN_VALUE] = HAS_EXIT_FLAG, [_GUARD_IP_RETURN_GENERATOR] = HAS_EXIT_FLAG, + [_RECORD_TOS] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_TOS_TYPE] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_NOS] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_4OS] = HAS_RECORDS_VALUE_FLAG, + [_RECORD_CALLABLE] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG, + [_RECORD_BOUND_METHOD] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG, + [_RECORD_CALLER_CODE] = HAS_RECORDS_VALUE_FLAG, }; const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = { @@ -5169,6 +5176,13 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_PY_FRAME_GENERAL_r01] = "_PY_FRAME_GENERAL_r01", [_PY_FRAME_KW] = "_PY_FRAME_KW", [_PY_FRAME_KW_r11] = "_PY_FRAME_KW_r11", + [_RECORD_4OS] = "_RECORD_4OS", + [_RECORD_BOUND_METHOD] = "_RECORD_BOUND_METHOD", + [_RECORD_CALLABLE] = "_RECORD_CALLABLE", + [_RECORD_CALLER_CODE] = "_RECORD_CALLER_CODE", + [_RECORD_NOS] = "_RECORD_NOS", + [_RECORD_TOS] = "_RECORD_TOS", + [_RECORD_TOS_TYPE] = "_RECORD_TOS_TYPE", [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", [_REPLACE_WITH_TRUE_r02] = "_REPLACE_WITH_TRUE_r02", [_REPLACE_WITH_TRUE_r12] = "_REPLACE_WITH_TRUE_r12", @@ -6043,6 +6057,20 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _GUARD_IP_RETURN_GENERATOR: return 0; + case _RECORD_TOS: + return 0; + case _RECORD_TOS_TYPE: + return 0; + case _RECORD_NOS: + return 0; + case _RECORD_4OS: + return 0; + case _RECORD_CALLABLE: + return 0; + case _RECORD_BOUND_METHOD: + return 0; + case _RECORD_CALLER_CODE: + return 0; default: return -1; } diff --git a/Makefile.pre.in b/Makefile.pre.in index 8531162943a..b362a4dfdc6 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2149,7 +2149,7 @@ Objects/mimalloc/page.o: $(srcdir)/Objects/mimalloc/page-queue.c .PHONY: regen-cases regen-cases: \ regen-opcode-ids regen-opcode-targets regen-uop-ids regen-opcode-metadata-py \ - regen-generated-cases regen-executor-cases regen-optimizer-cases \ + regen-generated-cases regen-executor-cases regen-optimizer-cases regen-record-functions \ regen-opcode-metadata regen-uop-metadata regen-test-cases regen-test-opcode-targets .PHONY: regen-opcode-ids @@ -2182,6 +2182,12 @@ regen-generated-cases: -o $(srcdir)/Python/generated_cases.c.h.new $(srcdir)/Python/bytecodes.c $(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new +.PHONY: regen-record-functions +regen-record-functions: + $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/record_function_generator.py \ + -o $(srcdir)/Python/record_functions.c.h.new $(srcdir)/Python/bytecodes.c + $(UPDATE_FILE) $(srcdir)/Python/record_functions.c.h $(srcdir)/Python/record_functions.c.h.new + .PHONY: regen-test-cases regen-test-cases: $(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/tier1_generator.py \ @@ -2234,7 +2240,8 @@ Python/ceval.o: \ $(srcdir)/Python/condvar.h \ $(srcdir)/Python/generated_cases.c.h \ $(srcdir)/Python/executor_cases.c.h \ - $(srcdir)/Python/opcode_targets.h + $(srcdir)/Python/opcode_targets.h \ + $(srcdir)/Python/record_functions.c.h Python/flowgraph.o: \ $(srcdir)/Include/internal/pycore_opcode_metadata.h diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index f4373a753ed..64c9ffeb4dc 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -7724,7 +7724,7 @@ oparg >>= 8; insert_exec_at--; } - int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg, NULL); + int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL); if (succ) { ENTER_TRACING(); } @@ -8018,10 +8018,21 @@ _PyStackRef attr; _PyStackRef *null; /* Skip 1 cache entry */ - // _CHECK_ATTR_CLASS + // _GUARD_TYPE_VERSION { owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UPDATE_MISS_STATS(LOAD_ATTR); + assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); + JUMP_TO_PREDICTED(LOAD_ATTR); + } + } + // _CHECK_ATTR_CLASS + { + uint32_t type_version = read_u32(&this_instr[4].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); if (!PyType_Check(owner_o)) { UPDATE_MISS_STATS(LOAD_ATTR); @@ -8035,17 +8046,6 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_TYPE_VERSION - { - uint32_t type_version = read_u32(&this_instr[4].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); - if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } // _LOAD_ATTR_CLASS { PyObject *descr = read_obj(&this_instr[6].cache); @@ -8595,14 +8595,6 @@ _PyStackRef owner; _PyStackRef new_frame; /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { - if (IS_PEP523_HOOKED(tstate)) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } // _GUARD_TYPE_VERSION { owner = stack_pointer[-1]; @@ -8615,6 +8607,14 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } + // _CHECK_PEP_523 + { + if (IS_PEP523_HOOKED(tstate)) { + UPDATE_MISS_STATS(LOAD_ATTR); + assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); + JUMP_TO_PREDICTED(LOAD_ATTR); + } + } /* Skip 2 cache entries */ // _LOAD_ATTR_PROPERTY_FRAME { @@ -10449,30 +10449,33 @@ next_instr += 1; INSTRUCTION_STATS(RETURN_GENERATOR); _PyStackRef res; - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (gen == NULL) { - JUMP_TO_LABEL(error); + // _RETURN_GENERATOR + { + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) { + JUMP_TO_LABEL(error); + } + assert(STACK_LEVEL() <= 2); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; + frame->instr_ptr++; + _PyFrame_Copy(frame, gen_frame); + assert(frame->frame_obj == NULL); + gen->gi_frame_state = FRAME_CREATED; + gen_frame->owner = FRAME_OWNED_BY_GENERATOR; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + frame = tstate->current_frame = prev; + LOAD_IP(frame->return_offset); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); + LLTRACE_RESUME_FRAME(); } - assert(STACK_LEVEL() <= 2); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; - frame->instr_ptr++; - _PyFrame_Copy(frame, gen_frame); - assert(frame->frame_obj == NULL); - gen->gi_frame_state = FRAME_CREATED; - gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *prev = frame->previous; - _PyThreadState_PopFrame(tstate, frame); - frame = tstate->current_frame = prev; - LOAD_IP(frame->return_offset); - stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); - LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -10489,21 +10492,24 @@ INSTRUCTION_STATS(RETURN_VALUE); _PyStackRef retval; _PyStackRef res; - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - assert(STACK_LEVEL() == 0); - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *dying = frame; - frame = tstate->current_frame = dying->previous; - _PyEval_FrameClearAndPop(tstate, dying); - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(frame->return_offset); - res = temp; - LLTRACE_RESUME_FRAME(); + // _RETURN_VALUE + { + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(STACK_LEVEL() == 0); + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *dying = frame; + frame = tstate->current_frame = dying->previous; + _PyEval_FrameClearAndPop(tstate, dying); + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(frame->return_offset); + res = temp; + LLTRACE_RESUME_FRAME(); + } stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -11892,6 +11898,9 @@ opcode == INTERPRETER_EXIT || (opcode >= MIN_INSTRUMENTED_OPCODE && opcode != ENTER_EXECUTOR) ); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + _PyJitTracerState *tracer = _tstate->jit_tracer_state; + assert(tracer != NULL); _PyFrame_SetStackPointer(frame, stack_pointer); int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11905,9 +11914,9 @@ } DISPATCH(); } - _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; - _PyJitTracerState *tracer = _tstate->jit_tracer_state; - assert(tracer != NULL); + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(tracer->prev_state.recorded_value); + stack_pointer = _PyFrame_GetStackPointer(frame); tracer->prev_state.instr = next_instr; PyObject *prev_code = PyStackRef_AsPyObjectBorrow(frame->f_executable); if (tracer->prev_state.instr_code != (PyCodeObject *)prev_code) { @@ -11921,6 +11930,11 @@ if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { (&next_instr[1])->counter = trigger_backoff_counter(); } + uint8_t record_func_index = _PyOpcode_RecordFunctionIndices[opcode]; + if (record_func_index) { + _Py_RecordFuncPtr doesnt_escape = _PyOpcode_RecordFunctions[record_func_index]; + doesnt_escape(frame, stack_pointer, oparg, &tracer->prev_state.recorded_value); + } DISPATCH_GOTO_NON_TRACING(); #else (void)prev_instr; @@ -12312,37 +12326,40 @@ INSTRUCTION_STATS(YIELD_VALUE); _PyStackRef retval; _PyStackRef value; - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); - assert(oparg == 0 || oparg == 1); - _PyStackRef temp = retval; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - tstate->exc_info = gen->gi_exc_state.previous_item; - gen->gi_exc_state.previous_item = NULL; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *gen_frame = frame; - frame = tstate->current_frame = frame->previous; - gen_frame->previous = NULL; - ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; - FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); - assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || + // _YIELD_VALUE + { + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); + assert(oparg == 0 || oparg == 1); + _PyStackRef temp = retval; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = tstate->current_frame = frame->previous; + gen_frame->previous = NULL; + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); + assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); + #if TIER_ONE + assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); - #endif - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - value = PyStackRef_MakeHeapSafe(temp); - LLTRACE_RESUME_FRAME(); + #endif + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); + value = PyStackRef_MakeHeapSafe(temp); + LLTRACE_RESUME_FRAME(); + } stack_pointer[0] = value; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 4c808016a00..9e41382240e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -568,6 +568,7 @@ dummy_func( macro(TO_BOOL_ALWAYS_TRUE) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _REPLACE_WITH_TRUE + POP_TOP; @@ -1107,6 +1108,7 @@ dummy_func( } macro(BINARY_OP_SUBSCR_GETITEM) = + _RECORD_TOS + unused/5 + // Skip over the counter and cache _CHECK_PEP_523 + _BINARY_OP_SUBSCR_CHECK_FUNC + @@ -1267,7 +1269,7 @@ dummy_func( // The stack effect here is a bit misleading. // retval is popped from the stack, but res // is pushed to a different frame, the callers' frame. - inst(RETURN_VALUE, (retval -- res)) { + op(_RETURN_VALUE, (retval -- res)) { assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); DEAD(retval); @@ -1291,9 +1293,13 @@ dummy_func( ERROR_IF(err); } + macro(RETURN_VALUE) = + _RECORD_CALLER_CODE + + _RETURN_VALUE; + macro(INSTRUMENTED_RETURN_VALUE) = _RETURN_VALUE_EVENT + - RETURN_VALUE; + _RETURN_VALUE; inst(GET_AITER, (obj -- iter)) { unaryfunc getter = NULL; @@ -1434,7 +1440,7 @@ dummy_func( _SEND_GEN_FRAME + _PUSH_FRAME; - inst(YIELD_VALUE, (retval -- value)) { + op(_YIELD_VALUE, (retval -- value)) { // NOTE: It's important that YIELD_VALUE never raises an exception! // The compiler treats any exception raised here as a failed close() // or throw() call. @@ -1470,6 +1476,10 @@ dummy_func( LLTRACE_RESUME_FRAME(); } + macro(YIELD_VALUE) = + _RECORD_CALLER_CODE + + _YIELD_VALUE; + tier1 op(_YIELD_VALUE_EVENT, (val -- val)) { int err = _Py_call_instrumentation_arg( tstate, PY_MONITORING_EVENT_PY_YIELD, @@ -1485,7 +1495,7 @@ dummy_func( macro(INSTRUMENTED_YIELD_VALUE) = _YIELD_VALUE_EVENT + - YIELD_VALUE; + _YIELD_VALUE; inst(POP_EXCEPT, (exc_value -- )) { _PyErr_StackItem *exc_info = tstate->exc_info; @@ -2445,6 +2455,7 @@ dummy_func( macro(LOAD_ATTR_INSTANCE_VALUE) = unused/1 + // Skip over the counter + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _CHECK_MANAGED_OBJECT_HAS_VALUES + _LOAD_ATTR_INSTANCE_VALUE + @@ -2526,6 +2537,7 @@ dummy_func( macro(LOAD_ATTR_WITH_HINT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _LOAD_ATTR_WITH_HINT + POP_TOP + @@ -2551,6 +2563,7 @@ dummy_func( macro(LOAD_ATTR_SLOT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _LOAD_ATTR_SLOT + // NOTE: This action may also deopt POP_TOP + @@ -2581,8 +2594,9 @@ dummy_func( macro(LOAD_ATTR_CLASS_WITH_METACLASS_CHECK) = unused/1 + - _CHECK_ATTR_CLASS + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + + _CHECK_ATTR_CLASS + _LOAD_ATTR_CLASS + _PUSH_NULL_CONDITIONAL; @@ -2604,8 +2618,9 @@ dummy_func( macro(LOAD_ATTR_PROPERTY) = unused/1 + - _CHECK_PEP_523 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + + _CHECK_PEP_523 + unused/2 + _LOAD_ATTR_PROPERTY_FRAME + _SAVE_RETURN_OFFSET + @@ -2715,6 +2730,7 @@ dummy_func( macro(STORE_ATTR_WITH_HINT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _STORE_ATTR_WITH_HINT + POP_TOP; @@ -2735,6 +2751,7 @@ dummy_func( macro(STORE_ATTR_SLOT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _STORE_ATTR_SLOT + POP_TOP; @@ -3021,7 +3038,7 @@ dummy_func( oparg >>= 8; insert_exec_at--; } - int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg, NULL); + int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL); if (succ) { ENTER_TRACING(); } @@ -3506,6 +3523,7 @@ dummy_func( } macro(FOR_ITER_GEN) = + _RECORD_NOS + unused/1 + _CHECK_PEP_523 + _FOR_ITER_GEN_FRAME + @@ -3640,6 +3658,7 @@ dummy_func( macro(LOAD_ATTR_METHOD_WITH_VALUES) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + _GUARD_KEYS_VERSION + @@ -3658,6 +3677,7 @@ dummy_func( macro(LOAD_ATTR_METHOD_NO_DICT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + unused/2 + _LOAD_ATTR_METHOD_NO_DICT; @@ -3672,6 +3692,7 @@ dummy_func( macro(LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT + _GUARD_KEYS_VERSION + @@ -3688,6 +3709,7 @@ dummy_func( macro(LOAD_ATTR_NONDESCRIPTOR_NO_DICT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + unused/2 + _LOAD_ATTR_NONDESCRIPTOR_NO_DICT; @@ -3711,6 +3733,7 @@ dummy_func( macro(LOAD_ATTR_METHOD_LAZY_DICT) = unused/1 + + _RECORD_TOS_TYPE + _GUARD_TYPE_VERSION + _CHECK_ATTR_METHOD_LAZY_DICT + unused/1 + @@ -3879,6 +3902,7 @@ dummy_func( } macro(CALL_PY_GENERAL) = + _RECORD_CALLABLE + unused/1 + // Skip over the counter _CHECK_PEP_523 + _CHECK_FUNCTION_VERSION + @@ -3909,6 +3933,7 @@ dummy_func( } macro(CALL_BOUND_METHOD_GENERAL) = + _RECORD_BOUND_METHOD + unused/1 + // Skip over the counter _CHECK_PEP_523 + _CHECK_METHOD_VERSION + @@ -3948,6 +3973,7 @@ dummy_func( } macro(CALL_NON_PY_GENERAL) = + _RECORD_CALLABLE + unused/1 + // Skip over the counter unused/2 + _CHECK_IS_NOT_PY_CALLABLE + @@ -4021,6 +4047,7 @@ dummy_func( } macro(CALL_BOUND_METHOD_EXACT_ARGS) = + _RECORD_BOUND_METHOD + unused/1 + // Skip over the counter _CHECK_PEP_523 + _CHECK_CALL_BOUND_METHOD_EXACT_ARGS + @@ -4035,6 +4062,7 @@ dummy_func( _PUSH_FRAME; macro(CALL_PY_EXACT_ARGS) = + _RECORD_CALLABLE + unused/1 + // Skip over the counter _CHECK_PEP_523 + _CHECK_FUNCTION_VERSION + @@ -4187,6 +4215,7 @@ dummy_func( } macro(CALL_ALLOC_AND_ENTER_INIT) = + _RECORD_CALLABLE + unused/1 + _CHECK_PEP_523 + _CHECK_AND_ALLOCATE_OBJECT + @@ -4227,6 +4256,7 @@ dummy_func( } macro(CALL_BUILTIN_CLASS) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_BUILTIN_CLASS + @@ -4262,6 +4292,7 @@ dummy_func( } macro(CALL_BUILTIN_O) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_BUILTIN_O + @@ -4294,6 +4325,7 @@ dummy_func( } macro(CALL_BUILTIN_FAST) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_BUILTIN_FAST + @@ -4320,6 +4352,7 @@ dummy_func( } macro(CALL_BUILTIN_FAST_WITH_KEYWORDS) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_BUILTIN_FAST_WITH_KEYWORDS + @@ -4463,6 +4496,7 @@ dummy_func( } macro(CALL_METHOD_DESCRIPTOR_O) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_METHOD_DESCRIPTOR_O + @@ -4505,6 +4539,7 @@ dummy_func( } macro(CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS + @@ -4543,6 +4578,7 @@ dummy_func( } macro(CALL_METHOD_DESCRIPTOR_NOARGS) = + _RECORD_CALLABLE + unused/1 + unused/2 + _CALL_METHOD_DESCRIPTOR_NOARGS + @@ -4968,6 +5004,7 @@ dummy_func( } macro(CALL_EX_PY) = + _RECORD_4OS + unused/1 + _CHECK_PEP_523 + _MAKE_CALLARGS_A_TUPLE + @@ -5037,7 +5074,7 @@ dummy_func( *ptr = attr; } - inst(RETURN_GENERATOR, (-- res)) { + op(_RETURN_GENERATOR, (-- res)) { assert(PyStackRef_FunctionCheck(frame->f_funcobj)); PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); @@ -5060,6 +5097,10 @@ dummy_func( LLTRACE_RESUME_FRAME(); } + macro(RETURN_GENERATOR) = + _RECORD_CALLER_CODE + + _RETURN_GENERATOR; + inst(BUILD_SLICE, (args[oparg] -- slice)) { PyObject *start_o = PyStackRef_AsPyObjectBorrow(args[0]); PyObject *stop_o = PyStackRef_AsPyObjectBorrow(args[1]); @@ -5588,7 +5629,7 @@ dummy_func( // Note: it's safe to use target->op.arg here instead of the oparg given by EXTENDED_ARG. // The invariant in the optimizer is the deopt target always points back to the first EXTENDED_ARG. // So setting it to anything else is wrong. - int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg, previous_executor); + int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, stack_pointer, chain_depth, exit, target->op.arg, previous_executor); exit->temperature = restart_backoff_counter(exit->temperature); if (succ) { GOTO_TIER_ONE_CONTINUE_TRACING(target); @@ -5607,37 +5648,77 @@ dummy_func( } tier2 op(_GUARD_IP__PUSH_FRAME, (ip/4 --)) { - _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(_PUSH_FRAME); + _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += IP_OFFSET_OF(_PUSH_FRAME); EXIT_IF(true); } } tier2 op(_GUARD_IP_YIELD_VALUE, (ip/4 --)) { - _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(YIELD_VALUE); + _Py_CODEUNIT *target = frame->instr_ptr + 1 + INLINE_CACHE_ENTRIES_SEND; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += IP_OFFSET_OF(YIELD_VALUE); + frame->instr_ptr += 1 + INLINE_CACHE_ENTRIES_SEND; EXIT_IF(true); } } tier2 op(_GUARD_IP_RETURN_VALUE, (ip/4 --)) { - _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(RETURN_VALUE); + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += IP_OFFSET_OF(RETURN_VALUE); + frame->instr_ptr += frame->return_offset; EXIT_IF(true); } } tier2 op(_GUARD_IP_RETURN_GENERATOR, (ip/4 --)) { - _Py_CODEUNIT *target = frame->instr_ptr + IP_OFFSET_OF(RETURN_GENERATOR); + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += IP_OFFSET_OF(RETURN_GENERATOR); + frame->instr_ptr += frame->return_offset; EXIT_IF(true); } } + /* Record ops for jit tracer. + * + * NOTE: These uops are NOPs for normal evaluation. + * They are only executed during trace recording */ + + tier2 op(_RECORD_TOS, (tos -- tos)) { + RECORD_VALUE(PyStackRef_AsPyObjectBorrow(tos)); + } + + tier2 op(_RECORD_TOS_TYPE, (tos -- tos)) { + RECORD_VALUE(Py_TYPE(PyStackRef_AsPyObjectBorrow(tos))); + } + + tier2 op(_RECORD_NOS, (nos, tos -- nos, tos)) { + RECORD_VALUE(PyStackRef_AsPyObjectBorrow(nos)); + } + + tier2 op(_RECORD_4OS, (value, _3os, nos, tos -- value, _3os, nos, tos)) { + RECORD_VALUE(PyStackRef_AsPyObjectBorrow(value)); + } + + tier2 op(_RECORD_CALLABLE, (func, self, args[oparg] -- func, self, args[oparg])) { + RECORD_VALUE(PyStackRef_AsPyObjectBorrow(func)); + } + + tier2 op(_RECORD_BOUND_METHOD, (callable, self, args[oparg] -- callable, self, args[oparg])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (Py_TYPE(callable_o) == &PyMethod_Type) { + PyObject *func = ((PyMethodObject *)callable_o)->im_func; + RECORD_VALUE(func); + } + } + + tier2 op(_RECORD_CALLER_CODE, ( -- )) { + _PyInterpreterFrame *caller_frame = frame->previous; + if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) { + PyCodeObject *code = _PyFrame_GetCode(frame->previous); + RECORD_VALUE(code); + } + } + label(pop_2_error) { stack_pointer -= 2; assert(WITHIN_STACK_BOUNDS()); @@ -5802,6 +5883,9 @@ dummy_func( opcode == INTERPRETER_EXIT || (opcode >= MIN_INSTRUMENTED_OPCODE && opcode != ENTER_EXECUTOR) ); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + _PyJitTracerState *tracer = _tstate->jit_tracer_state; + assert(tracer != NULL); int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0); if (full) { LEAVE_TRACING(); @@ -5809,13 +5893,7 @@ dummy_func( ERROR_IF(err < 0); DISPATCH(); } - // Super instructions. Instruction deopted. There's a mismatch in what the stack expects - // in the optimizer. So we have to reflect in the trace correctly. - _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; - // JIT should have disabled super instructions, as we can - // do these optimizations ourselves in the JIT. - _PyJitTracerState *tracer = _tstate->jit_tracer_state; - assert(tracer != NULL); + Py_CLEAR(tracer->prev_state.recorded_value); tracer->prev_state.instr = next_instr; PyObject *prev_code = PyStackRef_AsPyObjectBorrow(frame->f_executable); if (tracer->prev_state.instr_code != (PyCodeObject *)prev_code) { @@ -5828,6 +5906,12 @@ dummy_func( if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { (&next_instr[1])->counter = trigger_backoff_counter(); } + + uint8_t record_func_index = _PyOpcode_RecordFunctionIndices[opcode]; + if (record_func_index) { + _Py_RecordFuncPtr doesnt_escape = _PyOpcode_RecordFunctions[record_func_index]; + doesnt_escape(frame, stack_pointer, oparg, &tracer->prev_state.recorded_value); + } DISPATCH_GOTO_NON_TRACING(); #else (void)prev_instr; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 8901c259525..339789b61d8 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -20150,7 +20150,7 @@ _PyExecutorObject *previous_executor = _PyExecutor_FromExit(exit); assert(tstate->current_executor == (PyObject *)previous_executor); int chain_depth = previous_executor->vm_data.chain_depth + !exit->is_control_flow; - int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg, previous_executor); + int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, stack_pointer, chain_depth, exit, target->op.arg, previous_executor); exit->temperature = restart_backoff_counter(exit->temperature); if (succ) { GOTO_TIER_ONE_CONTINUE_TRACING(target); @@ -20171,11 +20171,9 @@ case _GUARD_IP__PUSH_FRAME_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - #define OFFSET_OF__PUSH_FRAME ((0)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF__PUSH_FRAME; if (true) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -20183,7 +20181,6 @@ } } SET_CURRENT_CACHED_VALUES(0); - #undef OFFSET_OF__PUSH_FRAME assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20192,11 +20189,9 @@ CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; - #define OFFSET_OF__PUSH_FRAME ((0)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF__PUSH_FRAME; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache0 = _stack_item_0; @@ -20206,7 +20201,6 @@ } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); - #undef OFFSET_OF__PUSH_FRAME assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20216,11 +20210,9 @@ assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; - #define OFFSET_OF__PUSH_FRAME ((0)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF__PUSH_FRAME; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; @@ -20232,7 +20224,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); - #undef OFFSET_OF__PUSH_FRAME assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20243,11 +20234,9 @@ _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; _PyStackRef _stack_item_2 = _tos_cache2; - #define OFFSET_OF__PUSH_FRAME ((0)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF__PUSH_FRAME; + _Py_CODEUNIT *target = frame->instr_ptr; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF__PUSH_FRAME; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache2 = _stack_item_2; @@ -20261,7 +20250,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(3); - #undef OFFSET_OF__PUSH_FRAME assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20269,11 +20257,10 @@ case _GUARD_IP_YIELD_VALUE_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + 1 + INLINE_CACHE_ENTRIES_SEND; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + frame->instr_ptr += 1 + INLINE_CACHE_ENTRIES_SEND; if (true) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -20281,7 +20268,6 @@ } } SET_CURRENT_CACHED_VALUES(0); - #undef OFFSET_OF_YIELD_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20290,11 +20276,10 @@ CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; - #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + 1 + INLINE_CACHE_ENTRIES_SEND; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + frame->instr_ptr += 1 + INLINE_CACHE_ENTRIES_SEND; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache0 = _stack_item_0; @@ -20304,7 +20289,6 @@ } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); - #undef OFFSET_OF_YIELD_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20314,11 +20298,10 @@ assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; - #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + 1 + INLINE_CACHE_ENTRIES_SEND; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + frame->instr_ptr += 1 + INLINE_CACHE_ENTRIES_SEND; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; @@ -20330,7 +20313,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); - #undef OFFSET_OF_YIELD_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20341,11 +20323,10 @@ _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; _PyStackRef _stack_item_2 = _tos_cache2; - #define OFFSET_OF_YIELD_VALUE ((1+INLINE_CACHE_ENTRIES_SEND)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_YIELD_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + 1 + INLINE_CACHE_ENTRIES_SEND; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_YIELD_VALUE; + frame->instr_ptr += 1 + INLINE_CACHE_ENTRIES_SEND; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache2 = _stack_item_2; @@ -20359,7 +20340,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(3); - #undef OFFSET_OF_YIELD_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20367,11 +20347,10 @@ case _GUARD_IP_RETURN_VALUE_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -20379,7 +20358,6 @@ } } SET_CURRENT_CACHED_VALUES(0); - #undef OFFSET_OF_RETURN_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20388,11 +20366,10 @@ CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; - #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache0 = _stack_item_0; @@ -20402,7 +20379,6 @@ } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); - #undef OFFSET_OF_RETURN_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20412,11 +20388,10 @@ assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; - #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; @@ -20428,7 +20403,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); - #undef OFFSET_OF_RETURN_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20439,11 +20413,10 @@ _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; _PyStackRef _stack_item_2 = _tos_cache2; - #define OFFSET_OF_RETURN_VALUE ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_VALUE; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_VALUE; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache2 = _stack_item_2; @@ -20457,7 +20430,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(3); - #undef OFFSET_OF_RETURN_VALUE assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20465,11 +20437,10 @@ case _GUARD_IP_RETURN_GENERATOR_r00: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); - #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); SET_CURRENT_CACHED_VALUES(0); @@ -20477,7 +20448,6 @@ } } SET_CURRENT_CACHED_VALUES(0); - #undef OFFSET_OF_RETURN_GENERATOR assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20486,11 +20456,10 @@ CHECK_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; - #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache0 = _stack_item_0; @@ -20500,7 +20469,6 @@ } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); - #undef OFFSET_OF_RETURN_GENERATOR assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20510,11 +20478,10 @@ assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; - #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache1 = _stack_item_1; @@ -20526,7 +20493,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); - #undef OFFSET_OF_RETURN_GENERATOR assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } @@ -20537,11 +20503,10 @@ _PyStackRef _stack_item_0 = _tos_cache0; _PyStackRef _stack_item_1 = _tos_cache1; _PyStackRef _stack_item_2 = _tos_cache2; - #define OFFSET_OF_RETURN_GENERATOR ((frame->return_offset)) PyObject *ip = (PyObject *)CURRENT_OPERAND0_64(); - _Py_CODEUNIT *target = frame->instr_ptr + OFFSET_OF_RETURN_GENERATOR; + _Py_CODEUNIT *target = frame->instr_ptr + frame->return_offset; if (target != (_Py_CODEUNIT *)ip) { - frame->instr_ptr += OFFSET_OF_RETURN_GENERATOR; + frame->instr_ptr += frame->return_offset; if (true) { UOP_STAT_INC(uopcode, miss); _tos_cache2 = _stack_item_2; @@ -20555,7 +20520,6 @@ _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(3); - #undef OFFSET_OF_RETURN_GENERATOR assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 77d9b182ada..d3c5f526efd 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7723,7 +7723,7 @@ oparg >>= 8; insert_exec_at--; } - int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg, NULL); + int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, stack_pointer, 0, NULL, oparg, NULL); if (succ) { ENTER_TRACING(); } @@ -8017,10 +8017,21 @@ _PyStackRef attr; _PyStackRef *null; /* Skip 1 cache entry */ - // _CHECK_ATTR_CLASS + // _GUARD_TYPE_VERSION { owner = stack_pointer[-1]; uint32_t type_version = read_u32(&this_instr[2].cache); + PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); + assert(type_version != 0); + if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { + UPDATE_MISS_STATS(LOAD_ATTR); + assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); + JUMP_TO_PREDICTED(LOAD_ATTR); + } + } + // _CHECK_ATTR_CLASS + { + uint32_t type_version = read_u32(&this_instr[4].cache); PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner); if (!PyType_Check(owner_o)) { UPDATE_MISS_STATS(LOAD_ATTR); @@ -8034,17 +8045,6 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } - // _GUARD_TYPE_VERSION - { - uint32_t type_version = read_u32(&this_instr[4].cache); - PyTypeObject *tp = Py_TYPE(PyStackRef_AsPyObjectBorrow(owner)); - assert(type_version != 0); - if (FT_ATOMIC_LOAD_UINT_RELAXED(tp->tp_version_tag) != type_version) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } // _LOAD_ATTR_CLASS { PyObject *descr = read_obj(&this_instr[6].cache); @@ -8594,14 +8594,6 @@ _PyStackRef owner; _PyStackRef new_frame; /* Skip 1 cache entry */ - // _CHECK_PEP_523 - { - if (IS_PEP523_HOOKED(tstate)) { - UPDATE_MISS_STATS(LOAD_ATTR); - assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); - JUMP_TO_PREDICTED(LOAD_ATTR); - } - } // _GUARD_TYPE_VERSION { owner = stack_pointer[-1]; @@ -8614,6 +8606,14 @@ JUMP_TO_PREDICTED(LOAD_ATTR); } } + // _CHECK_PEP_523 + { + if (IS_PEP523_HOOKED(tstate)) { + UPDATE_MISS_STATS(LOAD_ATTR); + assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR)); + JUMP_TO_PREDICTED(LOAD_ATTR); + } + } /* Skip 2 cache entries */ // _LOAD_ATTR_PROPERTY_FRAME { @@ -10446,30 +10446,33 @@ next_instr += 1; INSTRUCTION_STATS(RETURN_GENERATOR); _PyStackRef res; - assert(PyStackRef_FunctionCheck(frame->f_funcobj)); - PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (gen == NULL) { - JUMP_TO_LABEL(error); + // _RETURN_GENERATOR + { + assert(PyStackRef_FunctionCheck(frame->f_funcobj)); + PyFunctionObject *func = (PyFunctionObject *)PyStackRef_AsPyObjectBorrow(frame->f_funcobj); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (gen == NULL) { + JUMP_TO_LABEL(error); + } + assert(STACK_LEVEL() <= 2); + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; + frame->instr_ptr++; + _PyFrame_Copy(frame, gen_frame); + assert(frame->frame_obj == NULL); + gen->gi_frame_state = FRAME_CREATED; + gen_frame->owner = FRAME_OWNED_BY_GENERATOR; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *prev = frame->previous; + _PyThreadState_PopFrame(tstate, frame); + frame = tstate->current_frame = prev; + LOAD_IP(frame->return_offset); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); + LLTRACE_RESUME_FRAME(); } - assert(STACK_LEVEL() <= 2); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = &gen->gi_iframe; - frame->instr_ptr++; - _PyFrame_Copy(frame, gen_frame); - assert(frame->frame_obj == NULL); - gen->gi_frame_state = FRAME_CREATED; - gen_frame->owner = FRAME_OWNED_BY_GENERATOR; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *prev = frame->previous; - _PyThreadState_PopFrame(tstate, frame); - frame = tstate->current_frame = prev; - LOAD_IP(frame->return_offset); - stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectStealMortal((PyObject *)gen); - LLTRACE_RESUME_FRAME(); stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -10486,21 +10489,24 @@ INSTRUCTION_STATS(RETURN_VALUE); _PyStackRef retval; _PyStackRef res; - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - assert(STACK_LEVEL() == 0); - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *dying = frame; - frame = tstate->current_frame = dying->previous; - _PyEval_FrameClearAndPop(tstate, dying); - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(frame->return_offset); - res = temp; - LLTRACE_RESUME_FRAME(); + // _RETURN_VALUE + { + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + _PyStackRef temp = PyStackRef_MakeHeapSafe(retval); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + assert(STACK_LEVEL() == 0); + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *dying = frame; + frame = tstate->current_frame = dying->previous; + _PyEval_FrameClearAndPop(tstate, dying); + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(frame->return_offset); + res = temp; + LLTRACE_RESUME_FRAME(); + } stack_pointer[0] = res; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); @@ -11889,6 +11895,9 @@ opcode == INTERPRETER_EXIT || (opcode >= MIN_INSTRUMENTED_OPCODE && opcode != ENTER_EXECUTOR) ); + _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; + _PyJitTracerState *tracer = _tstate->jit_tracer_state; + assert(tracer != NULL); _PyFrame_SetStackPointer(frame, stack_pointer); int full = !_PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr, stop_tracing ? _DEOPT : 0); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -11902,9 +11911,9 @@ } DISPATCH(); } - _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; - _PyJitTracerState *tracer = _tstate->jit_tracer_state; - assert(tracer != NULL); + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_CLEAR(tracer->prev_state.recorded_value); + stack_pointer = _PyFrame_GetStackPointer(frame); tracer->prev_state.instr = next_instr; PyObject *prev_code = PyStackRef_AsPyObjectBorrow(frame->f_executable); if (tracer->prev_state.instr_code != (PyCodeObject *)prev_code) { @@ -11918,6 +11927,11 @@ if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { (&next_instr[1])->counter = trigger_backoff_counter(); } + uint8_t record_func_index = _PyOpcode_RecordFunctionIndices[opcode]; + if (record_func_index) { + _Py_RecordFuncPtr doesnt_escape = _PyOpcode_RecordFunctions[record_func_index]; + doesnt_escape(frame, stack_pointer, oparg, &tracer->prev_state.recorded_value); + } DISPATCH_GOTO_NON_TRACING(); #else (void)prev_instr; @@ -12309,37 +12323,40 @@ INSTRUCTION_STATS(YIELD_VALUE); _PyStackRef retval; _PyStackRef value; - retval = stack_pointer[-1]; - assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); - frame->instr_ptr++; - PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); - assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); - assert(oparg == 0 || oparg == 1); - _PyStackRef temp = retval; - stack_pointer += -1; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - tstate->exc_info = gen->gi_exc_state.previous_item; - gen->gi_exc_state.previous_item = NULL; - _Py_LeaveRecursiveCallPy(tstate); - _PyInterpreterFrame *gen_frame = frame; - frame = tstate->current_frame = frame->previous; - gen_frame->previous = NULL; - ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; - FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); - assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || + // _YIELD_VALUE + { + retval = stack_pointer[-1]; + assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); + frame->instr_ptr++; + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); + assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); + assert(oparg == 0 || oparg == 1); + _PyStackRef temp = retval; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + tstate->exc_info = gen->gi_exc_state.previous_item; + gen->gi_exc_state.previous_item = NULL; + _Py_LeaveRecursiveCallPy(tstate); + _PyInterpreterFrame *gen_frame = frame; + frame = tstate->current_frame = frame->previous; + gen_frame->previous = NULL; + ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; + FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); + assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); + #if TIER_ONE + assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); - #endif - stack_pointer = _PyFrame_GetStackPointer(frame); - LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); - value = PyStackRef_MakeHeapSafe(temp); - LLTRACE_RESUME_FRAME(); + #endif + stack_pointer = _PyFrame_GetStackPointer(frame); + LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); + value = PyStackRef_MakeHeapSafe(temp); + LLTRACE_RESUME_FRAME(); + } stack_pointer[0] = value; stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); diff --git a/Python/optimizer.c b/Python/optimizer.c index 2802ef17dbf..e4e18f14bdc 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -955,6 +955,11 @@ _PyJit_translate_single_bytecode_to_trace( assert(next->op.code == STORE_FAST); operand = next->op.arg; } + else if (_PyUop_Flags[uop] & HAS_RECORDS_VALUE_FLAG) { + PyObject *recorded_value = tracer->prev_state.recorded_value; + tracer->prev_state.recorded_value = NULL; + operand = (uintptr_t)recorded_value; + } // All other instructions ADD_TO_TRACE(uop, oparg, operand, target); } @@ -997,7 +1002,7 @@ _PyJit_translate_single_bytecode_to_trace( Py_NO_INLINE int _PyJit_TryInitializeTracing( PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr, - _Py_CODEUNIT *start_instr, _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, + _Py_CODEUNIT *start_instr, _Py_CODEUNIT *close_loop_instr, _PyStackRef *stack_pointer, int chain_depth, _PyExitData *exit, int oparg, _PyExecutorObject *current_executor) { _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate; @@ -1048,14 +1053,20 @@ _PyJit_TryInitializeTracing( tracer->initial_state.func = (PyFunctionObject *)Py_NewRef(func); tracer->initial_state.executor = (_PyExecutorObject *)Py_XNewRef(current_executor); tracer->initial_state.exit = exit; - tracer->initial_state.stack_depth = curr_stackdepth; + tracer->initial_state.stack_depth = stack_pointer - _PyFrame_Stackbase(frame); tracer->initial_state.chain_depth = chain_depth; tracer->prev_state.dependencies_still_valid = true; tracer->prev_state.instr_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame)); tracer->prev_state.instr = curr_instr; tracer->prev_state.instr_frame = frame; tracer->prev_state.instr_oparg = oparg; - tracer->prev_state.instr_stacklevel = curr_stackdepth; + tracer->prev_state.instr_stacklevel = tracer->initial_state.stack_depth; + tracer->prev_state.recorded_value = NULL; + uint8_t record_func_index = _PyOpcode_RecordFunctionIndices[curr_instr->op.code]; + if (record_func_index) { + _Py_RecordFuncPtr record_func = _PyOpcode_RecordFunctions[record_func_index]; + record_func(frame, stack_pointer, oparg, &tracer->prev_state.recorded_value); + } assert(curr_instr->op.code == JUMP_BACKWARD_JIT || (exit != NULL)); tracer->initial_state.jump_backward_instr = curr_instr; @@ -1099,6 +1110,7 @@ _PyJit_FinalizeTracing(PyThreadState *tstate, int err) Py_CLEAR(tracer->initial_state.func); Py_CLEAR(tracer->initial_state.executor); Py_CLEAR(tracer->prev_state.instr_code); + Py_CLEAR(tracer->prev_state.recorded_value); uop_buffer_init(&tracer->code_buffer, &tracer->uop_array[0], UOP_MAX_TRACE_LENGTH); tracer->is_tracing = false; } @@ -1526,6 +1538,10 @@ uop_optimize( buffer[pc].opcode = opcode + oparg + 1 - _PyUop_Replication[opcode].start; assert(strncmp(_PyOpcode_uop_name[buffer[pc].opcode], _PyOpcode_uop_name[opcode], strlen(_PyOpcode_uop_name[opcode])) == 0); } + else if (_PyUop_Flags[opcode] & HAS_RECORDS_VALUE_FLAG) { + Py_XDECREF((PyObject *)(uintptr_t)buffer[pc].operand0); + buffer[pc].opcode = _NOP; + } else if (is_terminator(&buffer[pc])) { break; } @@ -1926,6 +1942,8 @@ _Py_Executors_InvalidateCold(PyInterpreterState *interp) _Py_Executors_InvalidateAll(interp, 0); } +#include "record_functions.c.h" + static int escape_angles(const char *input, Py_ssize_t size, char *buffer) { int written = 0; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 5a3480ab316..1f6a64026d8 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -177,6 +177,7 @@ dummy_func(void) { op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { assert(type_version); + assert(this_instr[-1].opcode == _RECORD_TOS_TYPE); if (sym_matches_type_version(owner, type_version)) { ADD_OP(_NOP, 0, 0); } else { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 9dc1da3c93b..e7b31ad6ac0 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1833,6 +1833,7 @@ owner = stack_pointer[-1]; uint32_t type_version = (uint32_t)this_instr->operand0; assert(type_version); + assert(this_instr[-1].opcode == _RECORD_TOS_TYPE); if (sym_matches_type_version(owner, type_version)) { ADD_OP(_NOP, 0, 0); } else { @@ -4176,5 +4177,33 @@ break; } + case _RECORD_TOS: { + break; + } + + case _RECORD_TOS_TYPE: { + break; + } + + case _RECORD_NOS: { + break; + } + + case _RECORD_4OS: { + break; + } + + case _RECORD_CALLABLE: { + break; + } + + case _RECORD_BOUND_METHOD: { + break; + } + + case _RECORD_CALLER_CODE: { + break; + } + /* _TRACE_RECORD is not a viable micro-op for tier 2 */ diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h new file mode 100644 index 00000000000..ba85ed752d2 --- /dev/null +++ b/Python/record_functions.c.h @@ -0,0 +1,115 @@ +// This file is generated by Tools/cases_generator/record_function_generator.py +// from: +// Python/bytecodes.c +// Do not edit! + +#ifdef TIER_ONE + #error "This file is for Tier 2 only" +#endif +void _PyOpcode_RecordFunction_TOS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef tos; + tos = stack_pointer[-1]; + *recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(tos); + Py_INCREF(*recorded_value); +} + +void _PyOpcode_RecordFunction_TOS_TYPE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef tos; + tos = stack_pointer[-1]; + *recorded_value = (PyObject *)Py_TYPE(PyStackRef_AsPyObjectBorrow(tos)); + Py_INCREF(*recorded_value); +} + +void _PyOpcode_RecordFunction_NOS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef nos; + nos = stack_pointer[-2]; + *recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(nos); + Py_INCREF(*recorded_value); +} + +void _PyOpcode_RecordFunction_4OS(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef value; + value = stack_pointer[-4]; + *recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(value); + Py_INCREF(*recorded_value); +} + +void _PyOpcode_RecordFunction_CALLABLE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef func; + func = stack_pointer[-2 - oparg]; + *recorded_value = (PyObject *)PyStackRef_AsPyObjectBorrow(func); + Py_INCREF(*recorded_value); +} + +void _PyOpcode_RecordFunction_BOUND_METHOD(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyStackRef callable; + callable = stack_pointer[-2 - oparg]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + if (Py_TYPE(callable_o) == &PyMethod_Type) { + PyObject *func = ((PyMethodObject *)callable_o)->im_func; + *recorded_value = (PyObject *)func; + Py_INCREF(*recorded_value); + } +} + +void _PyOpcode_RecordFunction_CALLER_CODE(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value) { + _PyInterpreterFrame *caller_frame = frame->previous; + if (caller_frame->owner < FRAME_OWNED_BY_INTERPRETER) { + PyCodeObject *code = _PyFrame_GetCode(frame->previous); + *recorded_value = (PyObject *)code; + Py_INCREF(*recorded_value); + } +} + +#define _RECORD_TOS_TYPE_INDEX 1 +#define _RECORD_TOS_INDEX 2 +#define _RECORD_CALLER_CODE_INDEX 3 +#define _RECORD_NOS_INDEX 4 +#define _RECORD_CALLABLE_INDEX 5 +#define _RECORD_BOUND_METHOD_INDEX 6 +#define _RECORD_4OS_INDEX 7 +const uint8_t _PyOpcode_RecordFunctionIndices[256] = { + [TO_BOOL_ALWAYS_TRUE] = _RECORD_TOS_TYPE_INDEX, + [BINARY_OP_SUBSCR_GETITEM] = _RECORD_TOS_INDEX, + [RETURN_VALUE] = _RECORD_CALLER_CODE_INDEX, + [YIELD_VALUE] = _RECORD_CALLER_CODE_INDEX, + [LOAD_ATTR_INSTANCE_VALUE] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_PROPERTY] = _RECORD_TOS_TYPE_INDEX, + [STORE_ATTR_WITH_HINT] = _RECORD_TOS_TYPE_INDEX, + [STORE_ATTR_SLOT] = _RECORD_TOS_TYPE_INDEX, + [FOR_ITER_GEN] = _RECORD_NOS_INDEX, + [LOAD_ATTR_METHOD_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_METHOD_NO_DICT] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = _RECORD_TOS_TYPE_INDEX, + [LOAD_ATTR_METHOD_LAZY_DICT] = _RECORD_TOS_TYPE_INDEX, + [CALL_PY_GENERAL] = _RECORD_CALLABLE_INDEX, + [CALL_BOUND_METHOD_GENERAL] = _RECORD_BOUND_METHOD_INDEX, + [CALL_NON_PY_GENERAL] = _RECORD_CALLABLE_INDEX, + [CALL_BOUND_METHOD_EXACT_ARGS] = _RECORD_BOUND_METHOD_INDEX, + [CALL_PY_EXACT_ARGS] = _RECORD_CALLABLE_INDEX, + [CALL_ALLOC_AND_ENTER_INIT] = _RECORD_CALLABLE_INDEX, + [CALL_BUILTIN_CLASS] = _RECORD_CALLABLE_INDEX, + [CALL_BUILTIN_O] = _RECORD_CALLABLE_INDEX, + [CALL_BUILTIN_FAST] = _RECORD_CALLABLE_INDEX, + [CALL_BUILTIN_FAST_WITH_KEYWORDS] = _RECORD_CALLABLE_INDEX, + [CALL_METHOD_DESCRIPTOR_O] = _RECORD_CALLABLE_INDEX, + [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = _RECORD_CALLABLE_INDEX, + [CALL_METHOD_DESCRIPTOR_NOARGS] = _RECORD_CALLABLE_INDEX, + [CALL_EX_PY] = _RECORD_4OS_INDEX, + [RETURN_GENERATOR] = _RECORD_CALLER_CODE_INDEX, +}; + +const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[8] = { + [0] = NULL, + [_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE, + [_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS, + [_RECORD_CALLER_CODE_INDEX] = _PyOpcode_RecordFunction_CALLER_CODE, + [_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS, + [_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE, + [_RECORD_BOUND_METHOD_INDEX] = _PyOpcode_RecordFunction_BOUND_METHOD, + [_RECORD_4OS_INDEX] = _PyOpcode_RecordFunction_4OS, +}; diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py index bad1a3eb048..890b0eb0bd7 100644 --- a/Tools/c-analyzer/cpython/_parser.py +++ b/Tools/c-analyzer/cpython/_parser.py @@ -80,6 +80,7 @@ def format_tsv_lines(lines): 'Python/generated_cases.c.h', 'Python/executor_cases.c.h', 'Python/optimizer_cases.c.h', + 'Python/record_functions.c.h', 'Python/opcode_targets.h', 'Modules/_testinternalcapi/test_targets.h', 'Modules/_testinternalcapi/test_cases.c.h', diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index 2001fb7c379..89f84364432 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -39,6 +39,7 @@ class Properties: uses_opcode: bool needs_guard_ip: bool unpredictable_jump: bool + records_value: bool tier: int | None = None const_oparg: int = -1 needs_prev: bool = False @@ -83,6 +84,7 @@ def from_list(properties: list["Properties"]) -> "Properties": no_save_ip=all(p.no_save_ip for p in properties), needs_guard_ip=any(p.needs_guard_ip for p in properties), unpredictable_jump=any(p.unpredictable_jump for p in properties), + records_value=any(p.records_value for p in properties), ) @property @@ -113,6 +115,7 @@ def infallible(self) -> bool: no_save_ip=False, needs_guard_ip=False, unpredictable_jump=False, + records_value=False, ) @@ -710,6 +713,8 @@ def has_error_without_pop(op: parser.CodeDef) -> bool: "_Py_set_eval_breaker_bit", "trigger_backoff_counter", "_PyThreadState_PopCStackRefSteal", + "doesnt_escape", + ) @@ -999,6 +1004,7 @@ def compute_properties(op: parser.CodeDef) -> Properties: or variable_used(op, "LOAD_IP") or variable_used(op, "DISPATCH_INLINED"), unpredictable_jump=unpredictable_jump, + records_value=variable_used(op, "RECORD_VALUE") ) def expand(items: list[StackItem], oparg: int) -> list[StackItem]: @@ -1124,6 +1130,7 @@ def add_macro( macro: parser.Macro, instructions: dict[str, Instruction], uops: dict[str, Uop] ) -> None: parts: list[Part] = [] + first = True for part in macro.uops: match part: case parser.OpName(): @@ -1134,7 +1141,13 @@ def add_macro( raise analysis_error( f"No Uop named {part.name}", macro.tokens[0] ) - parts.append(uops[part.name]) + uop = uops[part.name] + if uop.properties.records_value and not first: + raise analysis_error( + f"Recording uop {part.name} must be first in macro", + macro.tokens[0]) + parts.append(uop) + first = False case parser.CacheEffect(): parts.append(Skip(part.size)) case _: diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py index 89bd801c61a..bdc4324b670 100644 --- a/Tools/cases_generator/generators_common.py +++ b/Tools/cases_generator/generators_common.py @@ -788,6 +788,8 @@ def cflags(p: Properties) -> str: flags.append("HAS_UNPREDICTABLE_JUMP_FLAG") if p.needs_guard_ip: flags.append("HAS_NEEDS_GUARD_IP_FLAG") + if p.records_value: + flags.append("HAS_RECORDS_VALUE_FLAG") if flags: return " | ".join(flags) else: diff --git a/Tools/cases_generator/opcode_metadata_generator.py b/Tools/cases_generator/opcode_metadata_generator.py index a31f57850f6..21407ad7df1 100644 --- a/Tools/cases_generator/opcode_metadata_generator.py +++ b/Tools/cases_generator/opcode_metadata_generator.py @@ -59,6 +59,7 @@ "PERIODIC", "UNPREDICTABLE_JUMP", "NEEDS_GUARD_IP", + "RECORDS_VALUE", ] diff --git a/Tools/cases_generator/record_function_generator.py b/Tools/cases_generator/record_function_generator.py new file mode 100644 index 00000000000..58d948f198c --- /dev/null +++ b/Tools/cases_generator/record_function_generator.py @@ -0,0 +1,134 @@ + +import argparse + +from analyzer import ( + Analysis, + Instruction, + analyze_files, + CodeSection, +) + +from generators_common import ( + DEFAULT_INPUT, + ROOT, + write_header, + emit_to, + TokenIterator, +) + +from cwriter import CWriter + +from tier1_generator import write_uop, Emitter, declare_variable +from typing import TextIO +from lexer import Token +from stack import Stack, Storage + +DEFAULT_OUTPUT = ROOT / "Python/recorder_functions.c.h" + + +class RecorderEmitter(Emitter): + def __init__(self, out: CWriter): + super().__init__(out, {}) + self._replacers["RECORD_VALUE"] = self.record_value + + def record_value( + self, + tkn: Token, + tkn_iter: TokenIterator, + uop: CodeSection, + storage: Storage, + inst: Instruction | None, + ) -> bool: + lparen = next(tkn_iter) + self.out.start_line() + self.emit("*recorded_value = (PyObject *)") + emit_to(self.out, tkn_iter, "RPAREN") + next(tkn_iter) # Semi colon + self.emit(";\n") + self.emit("Py_INCREF(*recorded_value);\n") + return True + + +def generate_recorder_functions(filenames: list[str], analysis: Analysis, out: CWriter) -> None: + write_header(__file__, filenames, outfile) + outfile.write( + """ +#ifdef TIER_ONE + #error "This file is for Tier 2 only" +#endif +""" + ) + args = "_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, int oparg, PyObject **recorded_value" + emitter = RecorderEmitter(out) + func_count = 0 + nop = analysis.instructions["NOP"] + function_table: dict[str, int] = dict() + for name, uop in analysis.uops.items(): + if not uop.properties.records_value: + continue + func_count += 1 + out.emit(f"void _PyOpcode_RecordFunction{uop.name[7:]}({args}) {{\n") + seen = {"unused"} + for var in uop.stack.inputs: + if var.used and var.name not in seen: + seen.add(var.name) + declare_variable(var, out) + stack = Stack() + write_uop(uop, emitter, 0, stack, nop, False) + out.start_line() + out.emit("}") + out.emit("\n\n") + +def generate_recorder_tables(analysis: Analysis, out: CWriter) -> None: + record_function_indexes: dict[str, int] = dict() + record_table: dict[str, str] = {} + index = 1 + for inst in analysis.instructions.values(): + if not inst.properties.records_value: + continue + for part in inst.parts: + if not part.properties.records_value: + continue + if part.name not in record_function_indexes: + record_function_indexes[part.name] = index + index += 1 + record_table[inst.name] = part.name + break + func_count = len(record_function_indexes) + + for name, index in record_function_indexes.items(): + out.emit(f"#define {name}_INDEX {index}\n") + args = "_PyJitTracerState *tracer, _PyInterpreterFrame *frame, _PyStackRef *stackpointer, int oparg" + out.emit("const uint8_t _PyOpcode_RecordFunctionIndices[256] = {\n") + for inst_name, record_name in record_table.items(): + out.emit(f" [{inst_name}] = {record_name}_INDEX,\n") + out.emit("};\n\n") + out.emit(f"const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[{func_count+1}] = {{\n") + out.emit(" [0] = NULL,\n") + for name in record_function_indexes: + out.emit(f" [{name}_INDEX] = _PyOpcode_RecordFunction{name[7:]},\n") + out.emit("};\n") + + +arg_parser = argparse.ArgumentParser( + description="Generate the record functions for the trace recorder.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +arg_parser.add_argument( + "-o", "--output", type=str, help="Generated code", default=DEFAULT_OUTPUT +) + +arg_parser.add_argument( + "input", nargs=argparse.REMAINDER, help="Instruction definition file(s)" +) + +if __name__ == "__main__": + args = arg_parser.parse_args() + if len(args.input) == 0: + args.input.append(DEFAULT_INPUT) + data = analyze_files(args.input) + with open(args.output, "w") as outfile: + out = CWriter(outfile, 0, False) + generate_recorder_functions(args.input, data, out) + generate_recorder_tables(data, out) diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py index c7ff5de681e..0334bec724d 100644 --- a/Tools/cases_generator/tier1_generator.py +++ b/Tools/cases_generator/tier1_generator.py @@ -56,7 +56,7 @@ def declare_variables(inst: Instruction, out: CWriter) -> None: raise analysis_error(ex.args[0], inst.where) from None seen = {"unused"} for part in inst.parts: - if not isinstance(part, Uop): + if not isinstance(part, Uop) or part.properties.records_value: continue for var in part.stack.inputs: if var.used and var.name not in seen: @@ -259,6 +259,8 @@ def generate_tier1_cases( offset = 1 # The instruction itself stack = Stack() for part in inst.parts: + if part.properties.records_value: + continue # Only emit braces if more than one uop insert_braces = len([p for p in inst.parts if isinstance(p, Uop)]) > 1 reachable, offset, stack = write_uop(part, emitter, offset, stack, inst, insert_braces) diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py index 9dc529753de..12da5bff254 100644 --- a/Tools/cases_generator/tier2_generator.py +++ b/Tools/cases_generator/tier2_generator.py @@ -207,12 +207,10 @@ def cache_items(self, stack: Stack, cached_items: int, zero_regs: bool) -> None: self.emit(f"SET_CURRENT_CACHED_VALUES({cached_items});\n") -def write_uop(uop: Uop, emitter: Tier2Emitter, stack: Stack, offset_strs: dict[str, tuple[str, str]], cached_items: int = 0) -> tuple[bool, Stack]: +def write_uop(uop: Uop, emitter: Tier2Emitter, stack: Stack, cached_items: int = 0) -> tuple[bool, Stack]: locals: dict[str, Local] = {} zero_regs = is_large(uop) or uop.properties.escapes try: - if name_offset_pair := offset_strs.get(uop.name): - emitter.emit(f"#define OFFSET_OF_{name_offset_pair[0]} ({name_offset_pair[1]})\n") emitter.out.start_line() if uop.properties.oparg: emitter.emit("oparg = CURRENT_OPARG();\n") @@ -237,8 +235,6 @@ def write_uop(uop: Uop, emitter: Tier2Emitter, stack: Stack, offset_strs: dict[s storage.stack._print(emitter.out) emitter.cache_items(storage.stack, cached_items, zero_regs) storage.flush(emitter.out) - if name_offset_pair: - emitter.emit(f"#undef OFFSET_OF_{name_offset_pair[0]}\n") return reachable, storage.stack except StackError as ex: raise analysis_error(ex.args[0], uop.body.open) from None @@ -251,29 +247,6 @@ def is_for_iter_test(uop: Uop) -> bool: "_GUARD_NOT_EXHAUSTED_TUPLE", "_FOR_ITER_TIER_TWO" ) -def populate_offset_strs(analysis: Analysis) -> dict[str, tuple[str, str]]: - offset_strs: dict[str, tuple[str, str]] = {} - for name, uop in analysis.uops.items(): - if not f"_GUARD_IP_{name}" in analysis.uops: - continue - tkn_iter = uop.body.tokens() - found = False - offset_str = "" - for token in tkn_iter: - if token.kind == "IDENTIFIER" and token.text == "LOAD_IP": - if found: - raise analysis_error("Cannot have two LOAD_IP in a guarded single uop.", uop.body.open) - offset = [] - while token.kind != "SEMI": - offset.append(token.text) - token = next(tkn_iter) - # 1: to remove the LOAD_IP text - offset_str = "".join(offset[1:]) - found = True - assert offset_str - offset_strs[f"_GUARD_IP_{name}"] = (name, offset_str) - return offset_strs - def generate_tier2( filenames: list[str], analysis: Analysis, outfile: TextIO, lines: bool ) -> None: @@ -287,7 +260,6 @@ def generate_tier2( """ ) out = CWriter(outfile, 2, lines) - offset_strs = populate_offset_strs(analysis) out.emit("\n") for name, uop in analysis.uops.items(): @@ -295,6 +267,8 @@ def generate_tier2( continue if uop.is_super(): continue + if uop.properties.records_value: + continue why_not_viable = uop.why_not_viable() if why_not_viable is not None: out.emit( @@ -310,7 +284,7 @@ def generate_tier2( stack = Stack() stack.push_cache([f"_tos_cache{i}" for i in range(inputs)], out) stack._print(out) - reachable, stack = write_uop(uop, emitter, stack, offset_strs, outputs) + reachable, stack = write_uop(uop, emitter, stack, outputs) out.start_line() if reachable: out.emit("assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());\n") diff --git a/Tools/cases_generator/uop_id_generator.py b/Tools/cases_generator/uop_id_generator.py index 6992806a95b..b059a4a169c 100644 --- a/Tools/cases_generator/uop_id_generator.py +++ b/Tools/cases_generator/uop_id_generator.py @@ -51,6 +51,8 @@ def generate_uop_ids( for name, uop in sorted(uops): if uop.properties.tier == 1: continue + if uop.properties.records_value: + continue for inputs, outputs, _ in sorted(get_uop_cache_depths(uop)): out.emit(f"#define {name}_r{inputs}{outputs} {next_id}\n") next_id += 1 diff --git a/Tools/cases_generator/uop_metadata_generator.py b/Tools/cases_generator/uop_metadata_generator.py index bdecb18d1d5..4c24435cbdb 100644 --- a/Tools/cases_generator/uop_metadata_generator.py +++ b/Tools/cases_generator/uop_metadata_generator.py @@ -28,6 +28,8 @@ def uop_cache_info(uop: Uop) -> list[str] | None: if uop.name == "_SPILL_OR_RELOAD": return None + if uop.properties.records_value: + return None default = "{ -1, -1, -1 },\n" table_size = MAX_CACHED_REGISTER + 1 entries = [ default ] * table_size @@ -96,7 +98,7 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("};\n\n") out.emit("const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {\n"); for uop in analysis.uops.values(): - if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): + if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super() and not uop.properties.records_value: for inputs, outputs, _ in get_uop_cache_depths(uop): out.emit(f"[{uop.name}_r{inputs}{outputs}] = {uop.name},\n") out.emit("};\n\n") @@ -110,8 +112,9 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: for uop in sorted(analysis.uops.values(), key=lambda t: t.name): if uop.is_viable() and uop.properties.tier != 1 and not uop.is_super(): out.emit(f'[{uop.name}] = "{uop.name}",\n') - for inputs, outputs, _ in get_uop_cache_depths(uop): - out.emit(f'[{uop.name}_r{inputs}{outputs}] = "{uop.name}_r{inputs}{outputs}",\n') + if not uop.properties.records_value: + for inputs, outputs, _ in get_uop_cache_depths(uop): + out.emit(f'[{uop.name}_r{inputs}{outputs}] = "{uop.name}_r{inputs}{outputs}",\n') out.emit("};\n") out.emit("int _PyUop_num_popped(int opcode, int oparg)\n{\n") out.emit("switch(opcode) {\n") @@ -132,7 +135,6 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None: out.emit("}\n\n") out.emit("#endif // NEED_OPCODE_METADATA\n\n") - def generate_uop_metadata( filenames: list[str], analysis: Analysis, outfile: TextIO ) -> None: From 89e6607e051ad4ffae8878cee1e0e6d72c618568 Mon Sep 17 00:00:00 2001 From: Hai Zhu Date: Tue, 3 Feb 2026 01:12:01 +0800 Subject: [PATCH 131/133] gh-139109: Replace `_CHECK_STACK_SPACE` with `_CHECK_STACK_SPACE_OPERAND` in JIT optiimizer (GH-144394) --- Lib/test/test_capi/test_opt.py | 61 ++++++++++++++++------------------ Python/bytecodes.c | 1 - Python/executor_cases.c.h | 26 --------------- Python/optimizer_bytecodes.c | 10 ++++-- Python/optimizer_cases.c.h | 8 ++++- 5 files changed, 43 insertions(+), 63 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index a379d1be2f9..437cc340fc9 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1022,7 +1022,6 @@ def return_hello(): # Constant narrowing allows constant folding for second comparison self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_sequential(self): def dummy12(x): return x - 1 @@ -1046,12 +1045,14 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # sequential calls: max(12, 13) == 13 - largest_stack = _testinternalcapi.get_co_framesize(dummy13.__code__) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + # Each call gets its own _CHECK_STACK_SPACE_OPERAND + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 2) + # Each _CHECK_STACK_SPACE_OPERAND has the framesize of its function + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_nested(self): def dummy12(x): return x + 3 @@ -1074,15 +1075,12 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # nested calls: 15 + 12 == 27 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy15.__code__) + - _testinternalcapi.get_co_framesize(dummy12.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 2) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy15.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls(self): def dummy12(x): return x + 3 @@ -1110,15 +1108,14 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # max(12, 18 + max(12, 13)) == 31 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy18.__code__) + - _testinternalcapi.get_co_framesize(dummy13.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 4) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy18.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls_different_order(self): # same as `several_calls` but with top-level calls reversed def dummy12(x): @@ -1147,15 +1144,15 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # max(18 + max(12, 13), 12) == 31 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy18.__code__) + - _testinternalcapi.get_co_framesize(dummy13.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 4) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy18.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_complex(self): def dummy0(x): return x @@ -1205,7 +1202,7 @@ def testfunc(n): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) - @unittest.skip("gh-139109 WIP") + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_checks_large_framesize(self): # Create a function with a large framesize. This ensures _CHECK_STACK_SPACE is # actually doing its job. Note that the resulting trace hits @@ -1267,7 +1264,7 @@ def testfunc(n): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) - @unittest.skip("gh-139109 WIP") + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_checks_recursion(self): def dummy15(x): while x > 0: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 9e41382240e..a990ab28577 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5372,7 +5372,6 @@ dummy_func( tier2 op(_CHECK_STACK_SPACE_OPERAND, (framesize/2 --)) { assert(framesize <= INT_MAX); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, framesize)); - DEOPT_IF(tstate->py_recursion_remaining <= 1); } op(_SAVE_RETURN_OFFSET, (--)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 339789b61d8..9c82f1acdef 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -18265,11 +18265,6 @@ SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } SET_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; @@ -18287,12 +18282,6 @@ SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); @@ -18313,13 +18302,6 @@ SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); @@ -18343,14 +18325,6 @@ SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = _stack_item_2; - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } _tos_cache2 = _stack_item_2; _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 1f6a64026d8..89c67071603 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1068,13 +1068,17 @@ dummy_func(void) { } op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { + assert((this_instr + 4)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 4)); + if (co == NULL) { + ctx->done = true; + break; + } + ADD_OP(_CHECK_STACK_SPACE_OPERAND, 0, co->co_framesize); } op (_CHECK_STACK_SPACE_OPERAND, (framesize/2 -- )) { (void)framesize; - /* We should never see _CHECK_STACK_SPACE_OPERANDs. - * They are only created at the end of this pass. */ - Py_UNREACHABLE(); } op(_PUSH_FRAME, (new_frame -- )) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index e7b31ad6ac0..61a30314c21 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2996,6 +2996,13 @@ } case _CHECK_STACK_SPACE: { + assert((this_instr + 4)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 4)); + if (co == NULL) { + ctx->done = true; + break; + } + ADD_OP(_CHECK_STACK_SPACE_OPERAND, 0, co->co_framesize); break; } @@ -3899,7 +3906,6 @@ case _CHECK_STACK_SPACE_OPERAND: { uint32_t framesize = (uint32_t)this_instr->operand0; (void)framesize; - Py_UNREACHABLE(); break; } From 29acc08c8dad664cd5713cb392e5beba65724c10 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 2 Feb 2026 20:00:12 +0200 Subject: [PATCH 132/133] gh-75572: Speed up test_xpickle (GH-144393) Run a long living subprocess which handles multiple requests instead of running a new subprocess for each request. --- Lib/test/test_xpickle.py | 99 ++++++++++++++++++++++++++------------ Lib/test/xpickle_worker.py | 35 +++++++++++--- 2 files changed, 96 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_xpickle.py b/Lib/test/test_xpickle.py index 158f27dce4f..d87c671d4f5 100644 --- a/Lib/test/test_xpickle.py +++ b/Lib/test/test_xpickle.py @@ -3,6 +3,7 @@ import io import os import pickle +import struct import subprocess import sys import unittest @@ -83,9 +84,19 @@ def have_python_version(py_version): return py_executable_map.get(py_version, None) -@support.requires_resource('cpu') +def read_exact(f, n): + buf = b'' + while len(buf) < n: + chunk = f.read(n - len(buf)) + if not chunk: + raise EOFError + buf += chunk + return buf + + class AbstractCompatTests(pickletester.AbstractPickleTests): py_version = None + worker = None @classmethod def setUpClass(cls): @@ -93,6 +104,7 @@ def setUpClass(cls): if not have_python_version(cls.py_version): py_version_str = ".".join(map(str, cls.py_version)) raise unittest.SkipTest(f'Python {py_version_str} not available') + cls.addClassCleanup(cls.finish_worker) # Override the default pickle protocol to match what xpickle worker # will be running. highest_protocol = highest_proto_for_py_version(cls.py_version) @@ -101,8 +113,32 @@ def setUpClass(cls): cls.enterClassContext(support.swap_attr(pickle, 'HIGHEST_PROTOCOL', highest_protocol)) - @staticmethod - def send_to_worker(python, data): + @classmethod + def start_worker(cls, python): + target = os.path.join(os.path.dirname(__file__), 'xpickle_worker.py') + worker = subprocess.Popen([*python, target], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + # For windows bpo-17023. + shell=is_windows) + cls.worker = worker + return worker + + @classmethod + def finish_worker(cls): + worker = cls.worker + if worker is None: + return + cls.worker = None + worker.stdin.close() + worker.stdout.close() + worker.stderr.close() + worker.terminate() + worker.wait() + + @classmethod + def send_to_worker(cls, python, data): """Bounce a pickled object through another version of Python. This will send data to a child process where it will be unpickled, then repickled and sent back to the parent process. @@ -112,33 +148,33 @@ def send_to_worker(python, data): Returns: The pickled data received from the child process. """ - target = os.path.join(os.path.dirname(__file__), 'xpickle_worker.py') - worker = subprocess.Popen([*python, target], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - # For windows bpo-17023. - shell=is_windows) - stdout, stderr = worker.communicate(data) - if worker.returncode == 0: - return stdout - # if the worker fails, it will write the exception to stdout - try: - exception = pickle.loads(stdout) - except (pickle.UnpicklingError, EOFError): - raise RuntimeError(stderr) - else: - if support.verbose > 1: - print() - print(f'{data = }') - print(f'{stdout = }') - print(f'{stderr = }') - if isinstance(exception, Exception): - # To allow for tests which test for errors. - raise exception - else: - raise RuntimeError(stderr) + worker = cls.worker + if worker is None: + worker = cls.start_worker(python) + try: + worker.stdin.write(struct.pack('!i', len(data)) + data) + worker.stdin.flush() + + size, = struct.unpack('!i', read_exact(worker.stdout, 4)) + if size > 0: + return read_exact(worker.stdout, size) + # if the worker fails, it will write the exception to stdout + if size < 0: + stdout = read_exact(worker.stdout, -size) + try: + exception = pickle.loads(stdout) + except (pickle.UnpicklingError, EOFError): + pass + else: + if isinstance(exception, Exception): + # To allow for tests which test for errors. + raise exception + _, stderr = worker.communicate() + raise RuntimeError(stderr) + except: + cls.finish_worker() + raise def dumps(self, arg, proto=0, **kwargs): # Skip tests that require buffer_callback arguments since @@ -148,9 +184,8 @@ def dumps(self, arg, proto=0, **kwargs): self.skipTest('Test does not support "buffer_callback" argument.') f = io.BytesIO() p = self.pickler(f, proto, **kwargs) - p.dump((proto, arg)) - f.seek(0) - data = bytes(f.read()) + p.dump(arg) + data = struct.pack('!i', proto) + f.getvalue() python = py_executable_map[self.py_version] return self.send_to_worker(python, data) diff --git a/Lib/test/xpickle_worker.py b/Lib/test/xpickle_worker.py index 3fd957f4a0b..1b49515123c 100644 --- a/Lib/test/xpickle_worker.py +++ b/Lib/test/xpickle_worker.py @@ -2,6 +2,7 @@ # pickles in a different Python version. import os import pickle +import struct import sys @@ -24,16 +25,38 @@ sources = f.read() exec(sources, vars(test_module)) +def read_exact(f, n): + buf = b'' + while len(buf) < n: + chunk = f.read(n - len(buf)) + if not chunk: + raise EOFError + buf += chunk + return buf in_stream = getattr(sys.stdin, 'buffer', sys.stdin) out_stream = getattr(sys.stdout, 'buffer', sys.stdout) try: - message = pickle.load(in_stream) - protocol, obj = message - pickle.dump(obj, out_stream, protocol) -except Exception as e: + while True: + size, = struct.unpack('!i', read_exact(in_stream, 4)) + if not size: + break + data = read_exact(in_stream, size) + protocol, = struct.unpack('!i', data[:4]) + obj = pickle.loads(data[4:]) + data = pickle.dumps(obj, protocol) + out_stream.write(struct.pack('!i', len(data)) + data) + out_stream.flush() +except Exception as exc: # dump the exception to stdout and write to stderr, then exit - pickle.dump(e, out_stream) - sys.stderr.write(repr(e)) + try: + data = pickle.dumps(exc) + out_stream.write(struct.pack('!i', -len(data)) + data) + out_stream.flush() + except Exception: + out_stream.write(struct.pack('!i', 0)) + out_stream.flush() + sys.stderr.write(repr(exc)) + sys.stderr.flush() sys.exit(1) From cb1dc91dcb1eb6637d1c79b34a0bab728939f717 Mon Sep 17 00:00:00 2001 From: Malcolm Smith Date: Tue, 3 Feb 2026 08:37:34 +0000 Subject: [PATCH 133/133] gh-144415: Android testbed fixes (#142912) Modifies handling of `.gz` files in Android app payloads, and ensures that when the Android testbed streams logs, stream flushes aren't treated as newlines. This improves the output of test suites that use "one dot per test" progress indicators. --- Android/android.py | 106 +++++++++++++----- Android/testbed/app/build.gradle.kts | 24 ++-- .../java/org/python/testbed/MainActivity.kt | 4 +- Lib/_android_support.py | 7 ++ Lib/test/test_android.py | 41 ++++--- ...-02-03-07-57-24.gh-issue-144415.U3L15r.rst | 3 + 6 files changed, 129 insertions(+), 56 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-02-03-07-57-24.gh-issue-144415.U3L15r.rst diff --git a/Android/android.py b/Android/android.py index d1a10be776e..629696be3db 100755 --- a/Android/android.py +++ b/Android/android.py @@ -15,6 +15,7 @@ from asyncio import wait_for from contextlib import asynccontextmanager from datetime import datetime, timezone +from enum import IntEnum, auto from glob import glob from os.path import abspath, basename, relpath from pathlib import Path @@ -61,6 +62,19 @@ hidden_output = [] +# Based on android/log.h in the NDK. +class LogPriority(IntEnum): + UNKNOWN = 0 + DEFAULT = auto() + VERBOSE = auto() + DEBUG = auto() + INFO = auto() + WARN = auto() + ERROR = auto() + FATAL = auto() + SILENT = auto() + + def log_verbose(context, line, stream=sys.stdout): if context.verbose: stream.write(line) @@ -505,21 +519,23 @@ async def logcat_task(context, initial_devices): pid = await wait_for(find_pid(serial), startup_timeout) # `--pid` requires API level 24 or higher. - args = [adb, "-s", serial, "logcat", "--pid", pid, "--format", "tag"] + # + # `--binary` mode is used in order to detect which messages end with a + # newline, which most of the other modes don't indicate (except `--format + # long`). For example, every time pytest runs a test, it prints a "." and + # flushes the stream. Each "." becomes a separate log message, but we should + # show them all on the same line. + args = [adb, "-s", serial, "logcat", "--pid", pid, "--binary"] logcat_started = False async with async_process( - *args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + *args, stdout=subprocess.PIPE, stderr=None ) as process: - while line := (await process.stdout.readline()).decode(*DECODE_ARGS): - if match := re.fullmatch(r"([A-Z])/(.*)", line, re.DOTALL): + while True: + try: + priority, tag, message = await read_logcat(process.stdout) logcat_started = True - level, message = match.groups() - else: - # If the regex doesn't match, this is either a logcat startup - # error, or the second or subsequent line of a multi-line - # message. Python won't produce multi-line messages, but other - # components might. - level, message = None, line + except asyncio.IncompleteReadError: + break # Exclude high-volume messages which are rarely useful. if context.verbose < 2 and "from python test_syslog" in message: @@ -527,25 +543,23 @@ async def logcat_task(context, initial_devices): # Put high-level messages on stderr so they're highlighted in the # buildbot logs. This will include Python's own stderr. - stream = ( - sys.stderr - if level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT) - else sys.stdout - ) + stream = sys.stderr if priority >= LogPriority.WARN else sys.stdout - # To simplify automated processing of the output, e.g. a buildbot - # posting a failure notice on a GitHub PR, we strip the level and - # tag indicators from Python's stdout and stderr. - for prefix in ["python.stdout: ", "python.stderr: "]: - if message.startswith(prefix): - global python_started - python_started = True - stream.write(message.removeprefix(prefix)) - break + # The app's stdout and stderr should be passed through transparently + # to our own corresponding streams. + if tag in ["python.stdout", "python.stderr"]: + global python_started + python_started = True + stream.write(message) + stream.flush() else: # Non-Python messages add a lot of noise, but they may - # sometimes help explain a failure. - log_verbose(context, line, stream) + # sometimes help explain a failure. Format them in the same way + # as `logcat --format tag`. + formatted = f"{priority.name[0]}/{tag}: {message}" + if not formatted.endswith("\n"): + formatted += "\n" + log_verbose(context, formatted, stream) # If the device disconnects while logcat is running, which always # happens in --managed mode, some versions of adb return non-zero. @@ -556,6 +570,44 @@ async def logcat_task(context, initial_devices): raise CalledProcessError(status, args) +# Read one binary log message from the given StreamReader. The message format is +# described at https://android.stackexchange.com/a/74660. All supported versions +# of Android use format version 2 or later. +async def read_logcat(stream): + async def read_bytes(size): + return await stream.readexactly(size) + + async def read_int(size): + return int.from_bytes(await read_bytes(size), "little") + + payload_len = await read_int(2) + if payload_len < 2: + # 1 byte for priority, 1 byte for null terminator of tag. + raise ValueError(f"payload length {payload_len} is too short") + + header_len = await read_int(2) + if header_len < 4: + raise ValueError(f"header length {header_len} is too short") + await read_bytes(header_len - 4) # Ignore other header fields. + + priority_int = await read_int(1) + try: + priority = LogPriority(priority_int) + except ValueError: + priority = LogPriority.UNKNOWN + + payload_fields = (await read_bytes(payload_len - 1)).split(b"\0") + if len(payload_fields) < 2: + raise ValueError( + f"payload {payload!r} does not contain at least 2 " + f"null-separated fields" + ) + tag, message, *_ = [ + field.decode(*DECODE_ARGS) for field in payload_fields + ] + return priority, tag, message + + def stop_app(serial): run([adb, "-s", serial, "shell", "am", "force-stop", APP_ID], log=False) diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts index 4f184cf42d5..53cdc591fa3 100644 --- a/Android/testbed/app/build.gradle.kts +++ b/Android/testbed/app/build.gradle.kts @@ -94,10 +94,13 @@ android { } // This controls the API level of the maxVersion managed emulator, which is used - // by CI and cibuildwheel. 34 takes up too much disk space (#142289), 35 has - // issues connecting to the internet (#142387), and 36 and later are not - // available as aosp_atd images yet. - targetSdk = 33 + // by CI and cibuildwheel. + // * 33 has excessive buffering in the logcat client + // (https://cs.android.com/android/_/android/platform/system/logging/+/d340721894f223327339010df59b0ac514308826). + // * 34 consumes too much disk space on GitHub Actions (#142289). + // * 35 has issues connecting to the internet (#142387). + // * 36 and later are not available as aosp_atd images yet. + targetSdk = 32 versionCode = 1 versionName = "1.0" @@ -130,9 +133,10 @@ android { path("src/main/c/CMakeLists.txt") } - // Set this property to something non-empty, otherwise it'll use the default - // list, which ignores asset directories beginning with an underscore. - aaptOptions.ignoreAssetsPattern = ".git" + // Set this property to something nonexistent but non-empty. Otherwise it'll use the + // default list, which ignores asset directories beginning with an underscore, and + // maybe also other files required by tests. + aaptOptions.ignoreAssetsPattern = "android-testbed-dont-ignore-anything" compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -234,6 +238,12 @@ androidComponents.onVariants { variant -> from(cwd) } } + + // A filename ending with .gz will be automatically decompressed + // while building the APK. Avoid this by adding a dash to the end, + // and add an extra dash to any filenames that already end with one. + // This will be undone in MainActivity.kt. + rename(""".*(\.gz|-)""", "$0-") } } diff --git a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt index 5727b0fe6c3..dc49cdb9a9f 100644 --- a/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt +++ b/Android/testbed/app/src/main/java/org/python/testbed/MainActivity.kt @@ -80,7 +80,9 @@ class PythonTestRunner(val context: Context) { continue } input.use { - File(targetSubdir, name).outputStream().use { output -> + // Undo the .gz workaround from build.gradle.kts. + val outputName = name.replace(Regex("""(.*)-"""), "$1") + File(targetSubdir, outputName).outputStream().use { output -> input.copyTo(output) } } diff --git a/Lib/_android_support.py b/Lib/_android_support.py index a439d03a144..320dab52acd 100644 --- a/Lib/_android_support.py +++ b/Lib/_android_support.py @@ -168,6 +168,13 @@ def write(self, prio, tag, message): # message. message = message.replace(b"\x00", b"\xc0\x80") + # On API level 30 and higher, Logcat will strip any number of leading + # newlines. This is visible in all `logcat` modes, even --binary. Work + # around this by adding a leading space, which shouldn't make any + # difference to the log's usability. + if message.startswith(b"\n"): + message = b" " + message + with self._lock: now = time() self._bucket_level += ( diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py index c6c4a15a7ee..31daafbc3d6 100644 --- a/Lib/test/test_android.py +++ b/Lib/test/test_android.py @@ -1,5 +1,4 @@ import io -import platform import queue import re import subprocess @@ -17,8 +16,6 @@ if sys.platform != "android": raise unittest.SkipTest("Android-specific") -api_level = platform.android_ver().api_level - # (name, level, fileno) STREAM_INFO = [("stdout", "I", 1), ("stderr", "W", 2)] @@ -179,14 +176,18 @@ def write(s, lines=None, *, write_len=None): # Multi-line messages. Avoid identical consecutive lines, as # they may activate "chatty" filtering and break the tests. - write("\nx", [""]) + # + # Additional spaces will appear in the output where necessary to + # protect leading newlines. + write("\nx", [" "]) write("\na\n", ["x", "a"]) - write("\n", [""]) + write("\n", [" "]) + write("\n\n", [" ", " "]) write("b\n", ["b"]) - write("c\n\n", ["c", ""]) + write("c\n\n", ["c", " "]) write("d\ne", ["d"]) write("xx", []) - write("f\n\ng", ["exxf", ""]) + write("f\n\ng", ["exxf", " "]) write("\n", ["g"]) # Since this is a line-based logging system, line buffering @@ -197,15 +198,16 @@ def write(s, lines=None, *, write_len=None): # However, buffering can be turned off completely if you want a # flush after every write. with self.reconfigure(stream, write_through=True): - write("\nx", ["", "x"]) - write("\na\n", ["", "a"]) - write("\n", [""]) + write("\nx", [" ", "x"]) + write("\na\n", [" ", "a"]) + write("\n", [" "]) + write("\n\n", [" ", " "]) write("b\n", ["b"]) - write("c\n\n", ["c", ""]) + write("c\n\n", ["c", " "]) write("d\ne", ["d", "e"]) write("xx", ["xx"]) - write("f\n\ng", ["f", "", "g"]) - write("\n", [""]) + write("f\n\ng", ["f", " ", "g"]) + write("\n", [" "]) # "\r\n" should be translated into "\n". write("hello\r\n", ["hello"]) @@ -325,19 +327,16 @@ def write(b, lines=None, *, write_len=None): # currently use `logcat -v tag`, which shows each line as if it # was a separate log entry, but strips a single trailing # newline. - # - # On newer versions of Android, all three of the above tools (or - # maybe Logcat itself) will also strip any number of leading - # newlines. - write(b"\nx", ["", "x"] if api_level < 30 else ["x"]) - write(b"\na\n", ["", "a"] if api_level < 30 else ["a"]) - write(b"\n", [""]) + write(b"\nx", [" ", "x"]) + write(b"\na\n", [" ", "a"]) + write(b"\n", [" "]) + write(b"\n\n", [" ", ""]) write(b"b\n", ["b"]) write(b"c\n\n", ["c", ""]) write(b"d\ne", ["d", "e"]) write(b"xx", ["xx"]) write(b"f\n\ng", ["f", "", "g"]) - write(b"\n", [""]) + write(b"\n", [" "]) # "\r\n" should be translated into "\n". write(b"hello\r\n", ["hello"]) diff --git a/Misc/NEWS.d/next/Tests/2026-02-03-07-57-24.gh-issue-144415.U3L15r.rst b/Misc/NEWS.d/next/Tests/2026-02-03-07-57-24.gh-issue-144415.U3L15r.rst new file mode 100644 index 00000000000..b3a8d463296 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-02-03-07-57-24.gh-issue-144415.U3L15r.rst @@ -0,0 +1,3 @@ +The Android testbed now distinguishes between stdout/stderr messages which +were triggered by a newline, and those triggered by a manual call to +``flush``. This fixes logging of progress indicators and similar content.