From 60f588478f0a3d88e86b97acecbcb569142f4636 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Sun, 7 May 2023 17:54:40 +0100
Subject: [PATCH 01/35] GH-100479: Fix pathlib test failure on WASI (#104215)

---
 Lib/test/test_pathlib.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 7586610833b063..e25c77f2ba8af6 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1655,7 +1655,8 @@ class P(_BasePurePathSubclass, self.cls):
         p = P(BASE, session_id=42)
         self.assertEqual(42, p.absolute().session_id)
         self.assertEqual(42, p.resolve().session_id)
-        self.assertEqual(42, p.with_segments('~').expanduser().session_id)
+        if not is_wasi:  # WASI has no user accounts.
+            self.assertEqual(42, p.with_segments('~').expanduser().session_id)
         self.assertEqual(42, (p / 'fileA').rename(p / 'fileB').session_id)
         self.assertEqual(42, (p / 'fileB').replace(p / 'fileA').session_id)
         if os_helper.can_symlink():

From 1b19bd1a88e6c410fc9cd08db48e0d35cfa8bb5a Mon Sep 17 00:00:00 2001
From: Alex Waygood <Alex.Waygood@Gmail.com>
Date: Sun, 7 May 2023 18:45:09 +0100
Subject: [PATCH 02/35] gh-103193: cache calls to `inspect._shadowed_dict` in
 `inspect.getattr_static` (#104267)

Co-authored-by: Carl Meyer <carl@oddbird.net>
---
 Doc/whatsnew/3.12.rst    |  7 ++++---
 Lib/inspect.py           |  8 ++++++--
 Lib/test/test_inspect.py | 22 ++++++++++++++++++++++
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index ec04178238b6b0..65b3e9ffb8072d 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -342,8 +342,9 @@ inspect
   (Contributed by Thomas Krennwallner in :issue:`35759`.)
 
 * The performance of :func:`inspect.getattr_static` has been considerably
-  improved. Most calls to the function should be around 2x faster than they
-  were in Python 3.11. (Contributed by Alex Waygood in :gh:`103193`.)
+  improved. Most calls to the function should be at least 2x faster than they
+  were in Python 3.11, and some may be 6x faster or more. (Contributed by Alex
+  Waygood in :gh:`103193`.)
 
 pathlib
 -------
@@ -597,7 +598,7 @@ typing
   :func:`runtime-checkable protocols <typing.runtime_checkable>` has changed
   significantly. Most ``isinstance()`` checks against protocols with only a few
   members should be at least 2x faster than in 3.11, and some may be 20x
-  faster or more. However, ``isinstance()`` checks against protocols with seven
+  faster or more. However, ``isinstance()`` checks against protocols with fourteen
   or more members may be slower than in Python 3.11. (Contributed by Alex
   Waygood in :gh:`74690` and :gh:`103193`.)
 
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 95da7fb71a3997..a64e85e4fd67a4 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1794,8 +1794,9 @@ def _check_class(klass, attr):
             return entry.__dict__[attr]
     return _sentinel
 
-def _shadowed_dict(klass):
-    for entry in _static_getmro(klass):
+@functools.lru_cache()
+def _shadowed_dict_from_mro_tuple(mro):
+    for entry in mro:
         dunder_dict = _get_dunder_dict_of_class(entry)
         if '__dict__' in dunder_dict:
             class_dict = dunder_dict['__dict__']
@@ -1805,6 +1806,9 @@ def _shadowed_dict(klass):
                 return class_dict
     return _sentinel
 
+def _shadowed_dict(klass):
+    return _shadowed_dict_from_mro_tuple(_static_getmro(klass))
+
 def getattr_static(obj, attr, default=_sentinel):
     """Retrieve attributes without triggering dynamic lookup via the
        descriptor protocol,  __getattr__ or __getattribute__.
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 42e3d709bd683f..dd0325a43e0f58 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -2111,6 +2111,28 @@ def __dict__(self):
         self.assertEqual(inspect.getattr_static(foo, 'a'), 3)
         self.assertFalse(test.called)
 
+    def test_mutated_mro(self):
+        test = self
+        test.called = False
+
+        class Foo(dict):
+            a = 3
+            @property
+            def __dict__(self):
+                test.called = True
+                return {}
+
+        class Bar(dict):
+            a = 4
+
+        class Baz(Bar): pass
+
+        baz = Baz()
+        self.assertEqual(inspect.getattr_static(baz, 'a'), 4)
+        Baz.__bases__ = (Foo,)
+        self.assertEqual(inspect.getattr_static(baz, 'a'), 3)
+        self.assertFalse(test.called)
+
     def test_custom_object_dict(self):
         test = self
         test.called = False

From 2c2dc61e8d01f44e5b7e63dd99196460a80905f1 Mon Sep 17 00:00:00 2001
From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Date: Sun, 7 May 2023 18:47:28 +0100
Subject: [PATCH 03/35] gh-104240: make _PyCompile_CodeGen support different
 compilation modes (#104241)

---
 Include/internal/pycore_compile.h             |  3 +-
 .../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 |  3 ++
 Lib/test/test_compiler_codegen.py             |  4 +++
 Modules/_testinternalcapi.c                   |  8 +++--
 Modules/clinic/_testinternalcapi.c.h          | 29 +++++++++++++------
 Python/compile.c                              |  8 +++--
 9 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h
index 4bd4ef57238f98..d2b12c91fe7a00 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -97,7 +97,8 @@ PyAPI_FUNC(PyObject*) _PyCompile_CodeGen(
         PyObject *ast,
         PyObject *filename,
         PyCompilerFlags *flags,
-        int optimize);
+        int optimize,
+        int compile_mode);
 
 PyAPI_FUNC(PyObject*) _PyCompile_OptimizeCfg(
         PyObject *instructions,
diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h
index 9377fd8526e3a2..7e495817981f06 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -847,6 +847,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(code));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(command));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(comment_factory));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(compile_mode));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(consts));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(context));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cookie));
diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h
index ed9b2bb44ddffc..8ebfee85c87c23 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -335,6 +335,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(code)
         STRUCT_FOR_ID(command)
         STRUCT_FOR_ID(comment_factory)
+        STRUCT_FOR_ID(compile_mode)
         STRUCT_FOR_ID(consts)
         STRUCT_FOR_ID(context)
         STRUCT_FOR_ID(cookie)
diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h
index 6ade8fb6eade03..7b9c73dd1edf3b 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -841,6 +841,7 @@ extern "C" {
     INIT_ID(code), \
     INIT_ID(command), \
     INIT_ID(comment_factory), \
+    INIT_ID(compile_mode), \
     INIT_ID(consts), \
     INIT_ID(context), \
     INIT_ID(cookie), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h
index 0b33ea187e60ff..8e086edbdf8193 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -858,6 +858,9 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     string = &_Py_ID(comment_factory);
     assert(_PyUnicode_CheckConsistency(string, 1));
     _PyUnicode_InternInPlace(interp, &string);
+    string = &_Py_ID(compile_mode);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    _PyUnicode_InternInPlace(interp, &string);
     string = &_Py_ID(consts);
     assert(_PyUnicode_CheckConsistency(string, 1));
     _PyUnicode_InternInPlace(interp, &string);
diff --git a/Lib/test/test_compiler_codegen.py b/Lib/test/test_compiler_codegen.py
index 022753e0c99483..ea57df9cd2400b 100644
--- a/Lib/test/test_compiler_codegen.py
+++ b/Lib/test/test_compiler_codegen.py
@@ -25,6 +25,8 @@ def test_if_expression(self):
             ('LOAD_CONST', 2, 1),
             exit_lbl,
             ('POP_TOP', None),
+            ('LOAD_CONST', 3),
+            ('RETURN_VALUE', None),
         ]
         self.codegen_test(snippet, expected)
 
@@ -46,5 +48,7 @@ def test_for_loop(self):
             ('JUMP', loop_lbl),
             exit_lbl,
             ('END_FOR', None),
+            ('LOAD_CONST', 0),
+            ('RETURN_VALUE', None),
         ]
         self.codegen_test(snippet, expected)
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index f35e3b48df9321..40ad6f88868daf 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -593,17 +593,19 @@ _testinternalcapi.compiler_codegen -> object
   ast: object
   filename: object
   optimize: int
+  compile_mode: int = 0
 
 Apply compiler code generation to an AST.
 [clinic start generated code]*/
 
 static PyObject *
 _testinternalcapi_compiler_codegen_impl(PyObject *module, PyObject *ast,
-                                        PyObject *filename, int optimize)
-/*[clinic end generated code: output=fbbbbfb34700c804 input=e9fbe6562f7f75e4]*/
+                                        PyObject *filename, int optimize,
+                                        int compile_mode)
+/*[clinic end generated code: output=40a68f6e13951cc8 input=a0e00784f1517cd7]*/
 {
     PyCompilerFlags *flags = NULL;
-    return _PyCompile_CodeGen(ast, filename, flags, optimize);
+    return _PyCompile_CodeGen(ast, filename, flags, optimize, compile_mode);
 }
 
 
diff --git a/Modules/clinic/_testinternalcapi.c.h b/Modules/clinic/_testinternalcapi.c.h
index 89573222572594..41dd50437956c4 100644
--- a/Modules/clinic/_testinternalcapi.c.h
+++ b/Modules/clinic/_testinternalcapi.c.h
@@ -9,7 +9,7 @@ preserve
 
 
 PyDoc_STRVAR(_testinternalcapi_compiler_codegen__doc__,
-"compiler_codegen($module, /, ast, filename, optimize)\n"
+"compiler_codegen($module, /, ast, filename, optimize, compile_mode=0)\n"
 "--\n"
 "\n"
 "Apply compiler code generation to an AST.");
@@ -19,7 +19,8 @@ PyDoc_STRVAR(_testinternalcapi_compiler_codegen__doc__,
 
 static PyObject *
 _testinternalcapi_compiler_codegen_impl(PyObject *module, PyObject *ast,
-                                        PyObject *filename, int optimize);
+                                        PyObject *filename, int optimize,
+                                        int compile_mode);
 
 static PyObject *
 _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
@@ -27,14 +28,14 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s
     PyObject *return_value = NULL;
     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
 
-    #define NUM_KEYWORDS 3
+    #define NUM_KEYWORDS 4
     static struct {
         PyGC_Head _this_is_not_used;
         PyObject_VAR_HEAD
         PyObject *ob_item[NUM_KEYWORDS];
     } _kwtuple = {
         .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
-        .ob_item = { &_Py_ID(ast), &_Py_ID(filename), &_Py_ID(optimize), },
+        .ob_item = { &_Py_ID(ast), &_Py_ID(filename), &_Py_ID(optimize), &_Py_ID(compile_mode), },
     };
     #undef NUM_KEYWORDS
     #define KWTUPLE (&_kwtuple.ob_base.ob_base)
@@ -43,19 +44,21 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s
     #  define KWTUPLE NULL
     #endif  // !Py_BUILD_CORE
 
-    static const char * const _keywords[] = {"ast", "filename", "optimize", NULL};
+    static const char * const _keywords[] = {"ast", "filename", "optimize", "compile_mode", NULL};
     static _PyArg_Parser _parser = {
         .keywords = _keywords,
         .fname = "compiler_codegen",
         .kwtuple = KWTUPLE,
     };
     #undef KWTUPLE
-    PyObject *argsbuf[3];
+    PyObject *argsbuf[4];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 3;
     PyObject *ast;
     PyObject *filename;
     int optimize;
+    int compile_mode = 0;
 
-    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 3, 0, argsbuf);
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 3, 4, 0, argsbuf);
     if (!args) {
         goto exit;
     }
@@ -65,7 +68,15 @@ _testinternalcapi_compiler_codegen(PyObject *module, PyObject *const *args, Py_s
     if (optimize == -1 && PyErr_Occurred()) {
         goto exit;
     }
-    return_value = _testinternalcapi_compiler_codegen_impl(module, ast, filename, optimize);
+    if (!noptargs) {
+        goto skip_optional_pos;
+    }
+    compile_mode = _PyLong_AsInt(args[3]);
+    if (compile_mode == -1 && PyErr_Occurred()) {
+        goto exit;
+    }
+skip_optional_pos:
+    return_value = _testinternalcapi_compiler_codegen_impl(module, ast, filename, optimize, compile_mode);
 
 exit:
     return return_value;
@@ -190,4 +201,4 @@ _testinternalcapi_assemble_code_object(PyObject *module, PyObject *const *args,
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=d5e08c9d67f9721f input=a9049054013a1b77]*/
+/*[clinic end generated code: output=ab661d56a14b1a1c input=a9049054013a1b77]*/
diff --git a/Python/compile.c b/Python/compile.c
index cbe5403aafbc87..f875e4e17e0a9f 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -7258,7 +7258,7 @@ cfg_to_instructions(cfg_builder *g)
 
 PyObject *
 _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
-                   int optimize)
+                   int optimize, int compile_mode)
 {
     PyObject *res = NULL;
 
@@ -7272,7 +7272,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
         return NULL;
     }
 
-    mod_ty mod = PyAST_obj2mod(ast, arena, 0 /* exec */);
+    mod_ty mod = PyAST_obj2mod(ast, arena, compile_mode);
     if (mod == NULL || !_PyAST_Validate(mod)) {
         _PyArena_Free(arena);
         return NULL;
@@ -7287,6 +7287,10 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
     if (compiler_codegen(c, mod) < 0) {
         goto finally;
     }
+    int addNone = mod->kind != Expression_kind;
+    if (add_return_at_end(c, addNone) < 0) {
+        return NULL;
+    }
 
     res = instr_sequence_to_instructions(INSTR_SEQUENCE(c));
 

From e8d77b03e08a4c7e7dde0830c5a12a0b41ff7c33 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Sun, 7 May 2023 20:07:07 +0100
Subject: [PATCH 04/35] GH-89812: Churn `pathlib.Path` methods (GH-104243)

Re-arrange `pathlib.Path` methods in source code. No other changes.

The methods are arranged as follows:

1. `stat()` and dependants (`exists()`, `is_dir()`, etc)
2. `open()` and dependants (`read_text()`, `write_bytes()`, etc)
3. `iterdir()` and dependants (`glob()`, `walk()`, etc)
4. All other `Path` methods

This patch prepares the ground for a new `_AbstractPath` class, which will
support the methods in groups 1, 2 and 3 above. By churning the methods
here, subsequent patches will be easier to review and less likely to break
things.
---
 Lib/pathlib.py | 606 ++++++++++++++++++++++++-------------------------
 1 file changed, 303 insertions(+), 303 deletions(-)

diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 480c354ce8b656..68255aa3e511ec 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -740,68 +740,164 @@ class Path(PurePath):
     """
     __slots__ = ()
 
-    def __init__(self, *args, **kwargs):
-        if kwargs:
-            msg = ("support for supplying keyword arguments to pathlib.PurePath "
-                   "is deprecated and scheduled for removal in Python {remove}")
-            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
-        super().__init__(*args)
+    def stat(self, *, follow_symlinks=True):
+        """
+        Return the result of the stat() system call on this path, like
+        os.stat() does.
+        """
+        return os.stat(self, follow_symlinks=follow_symlinks)
 
-    def __new__(cls, *args, **kwargs):
-        if cls is Path:
-            cls = WindowsPath if os.name == 'nt' else PosixPath
-        return object.__new__(cls)
+    def lstat(self):
+        """
+        Like stat(), except if the path points to a symlink, the symlink's
+        status information is returned, rather than its target's.
+        """
+        return self.stat(follow_symlinks=False)
 
-    def _make_child_relpath(self, name):
-        path_str = str(self)
-        tail = self._tail
-        if tail:
-            path_str = f'{path_str}{self._flavour.sep}{name}'
-        elif path_str != '.':
-            path_str = f'{path_str}{name}'
-        else:
-            path_str = name
-        path = self.with_segments(path_str)
-        path._str = path_str
-        path._drv = self.drive
-        path._root = self.root
-        path._tail_cached = tail + [name]
-        return path
 
-    def __enter__(self):
-        # In previous versions of pathlib, __exit__() marked this path as
-        # closed; subsequent attempts to perform I/O would raise an IOError.
-        # This functionality was never documented, and had the effect of
-        # making Path objects mutable, contrary to PEP 428.
-        # In Python 3.9 __exit__() was made a no-op.
-        # In Python 3.11 __enter__() began emitting DeprecationWarning.
-        # In Python 3.13 __enter__() and __exit__() should be removed.
-        warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled "
-                      "for removal in Python 3.13; Path objects as a context "
-                      "manager is a no-op",
-                      DeprecationWarning, stacklevel=2)
-        return self
+    # Convenience functions for querying the stat results
 
-    def __exit__(self, t, v, tb):
-        pass
+    def exists(self, *, follow_symlinks=True):
+        """
+        Whether this path exists.
 
-    # Public API
+        This method normally follows symlinks; to check whether a symlink exists,
+        add the argument follow_symlinks=False.
+        """
+        try:
+            self.stat(follow_symlinks=follow_symlinks)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+        return True
 
-    @classmethod
-    def cwd(cls):
-        """Return a new path pointing to the current working directory."""
-        # We call 'absolute()' rather than using 'os.getcwd()' directly to
-        # enable users to replace the implementation of 'absolute()' in a
-        # subclass and benefit from the new behaviour here. This works because
-        # os.path.abspath('.') == os.getcwd().
-        return cls().absolute()
+    def is_dir(self):
+        """
+        Whether this path is a directory.
+        """
+        try:
+            return S_ISDIR(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
 
-    @classmethod
-    def home(cls):
-        """Return a new path pointing to the user's home directory (as
-        returned by os.path.expanduser('~')).
+    def is_file(self):
         """
-        return cls("~").expanduser()
+        Whether this path is a regular file (also True for symlinks pointing
+        to regular files).
+        """
+        try:
+            return S_ISREG(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+
+    def is_mount(self):
+        """
+        Check if this path is a mount point
+        """
+        return self._flavour.ismount(self)
+
+    def is_symlink(self):
+        """
+        Whether this path is a symbolic link.
+        """
+        try:
+            return S_ISLNK(self.lstat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+
+    def is_junction(self):
+        """
+        Whether this path is a junction.
+        """
+        return self._flavour.isjunction(self)
+
+    def is_block_device(self):
+        """
+        Whether this path is a block device.
+        """
+        try:
+            return S_ISBLK(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+
+    def is_char_device(self):
+        """
+        Whether this path is a character device.
+        """
+        try:
+            return S_ISCHR(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+
+    def is_fifo(self):
+        """
+        Whether this path is a FIFO.
+        """
+        try:
+            return S_ISFIFO(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
+
+    def is_socket(self):
+        """
+        Whether this path is a socket.
+        """
+        try:
+            return S_ISSOCK(self.stat().st_mode)
+        except OSError as e:
+            if not _ignore_error(e):
+                raise
+            # Path doesn't exist or is a broken symlink
+            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
+            return False
+        except ValueError:
+            # Non-encodable path
+            return False
 
     def samefile(self, other_path):
         """Return whether other_path is the same or not as this file
@@ -814,6 +910,51 @@ def samefile(self, other_path):
             other_st = self.with_segments(other_path).stat()
         return self._flavour.samestat(st, other_st)
 
+    def open(self, mode='r', buffering=-1, encoding=None,
+             errors=None, newline=None):
+        """
+        Open the file pointed by this path and return a file object, as
+        the built-in open() function does.
+        """
+        if "b" not in mode:
+            encoding = io.text_encoding(encoding)
+        return io.open(self, mode, buffering, encoding, errors, newline)
+
+    def read_bytes(self):
+        """
+        Open the file in bytes mode, read it, and close the file.
+        """
+        with self.open(mode='rb') as f:
+            return f.read()
+
+    def read_text(self, encoding=None, errors=None):
+        """
+        Open the file in text mode, read it, and close the file.
+        """
+        encoding = io.text_encoding(encoding)
+        with self.open(mode='r', encoding=encoding, errors=errors) as f:
+            return f.read()
+
+    def write_bytes(self, data):
+        """
+        Open the file in bytes mode, write to it, and close the file.
+        """
+        # type-check for the buffer interface before truncating the file
+        view = memoryview(data)
+        with self.open(mode='wb') as f:
+            return f.write(view)
+
+    def write_text(self, data, encoding=None, errors=None, newline=None):
+        """
+        Open the file in text mode, write to it, and close the file.
+        """
+        if not isinstance(data, str):
+            raise TypeError('data must be str, not %s' %
+                            data.__class__.__name__)
+        encoding = io.text_encoding(encoding)
+        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
+            return f.write(data)
+
     def iterdir(self):
         """Yield path objects of the directory contents.
 
@@ -829,6 +970,22 @@ def _scandir(self):
         # includes scandir(), which is used to implement glob().
         return os.scandir(self)
 
+    def _make_child_relpath(self, name):
+        path_str = str(self)
+        tail = self._tail
+        if tail:
+            path_str = f'{path_str}{self._flavour.sep}{name}'
+        elif path_str != '.':
+            path_str = f'{path_str}{name}'
+        else:
+            path_str = name
+        path = self.with_segments(path_str)
+        path._str = path_str
+        path._drv = self.drive
+        path._root = self.root
+        path._tail_cached = tail + [name]
+        return path
+
     def glob(self, pattern, *, case_sensitive=None):
         """Iterate over this subtree and yield all existing files (of any
         kind, including directories) matching the given relative pattern.
@@ -860,6 +1017,98 @@ def rglob(self, pattern, *, case_sensitive=None):
         for p in selector.select_from(self):
             yield p
 
+    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
+        """Walk the directory tree from this directory, similar to os.walk()."""
+        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
+        paths = [self]
+
+        while paths:
+            path = paths.pop()
+            if isinstance(path, tuple):
+                yield path
+                continue
+
+            # We may not have read permission for self, in which case we can't
+            # get a list of the files the directory contains. os.walk()
+            # always suppressed the exception in that instance, rather than
+            # blow up for a minor reason when (say) a thousand readable
+            # directories are still left to visit. That logic is copied here.
+            try:
+                scandir_it = path._scandir()
+            except OSError as error:
+                if on_error is not None:
+                    on_error(error)
+                continue
+
+            with scandir_it:
+                dirnames = []
+                filenames = []
+                for entry in scandir_it:
+                    try:
+                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
+                    except OSError:
+                        # Carried over from os.path.isdir().
+                        is_dir = False
+
+                    if is_dir:
+                        dirnames.append(entry.name)
+                    else:
+                        filenames.append(entry.name)
+
+            if top_down:
+                yield path, dirnames, filenames
+            else:
+                paths.append((path, dirnames, filenames))
+
+            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]
+
+    def __init__(self, *args, **kwargs):
+        if kwargs:
+            msg = ("support for supplying keyword arguments to pathlib.PurePath "
+                   "is deprecated and scheduled for removal in Python {remove}")
+            warnings._deprecated("pathlib.PurePath(**kwargs)", msg, remove=(3, 14))
+        super().__init__(*args)
+
+    def __new__(cls, *args, **kwargs):
+        if cls is Path:
+            cls = WindowsPath if os.name == 'nt' else PosixPath
+        return object.__new__(cls)
+
+    def __enter__(self):
+        # In previous versions of pathlib, __exit__() marked this path as
+        # closed; subsequent attempts to perform I/O would raise an IOError.
+        # This functionality was never documented, and had the effect of
+        # making Path objects mutable, contrary to PEP 428.
+        # In Python 3.9 __exit__() was made a no-op.
+        # In Python 3.11 __enter__() began emitting DeprecationWarning.
+        # In Python 3.13 __enter__() and __exit__() should be removed.
+        warnings.warn("pathlib.Path.__enter__() is deprecated and scheduled "
+                      "for removal in Python 3.13; Path objects as a context "
+                      "manager is a no-op",
+                      DeprecationWarning, stacklevel=2)
+        return self
+
+    def __exit__(self, t, v, tb):
+        pass
+
+    # Public API
+
+    @classmethod
+    def cwd(cls):
+        """Return a new path pointing to the current working directory."""
+        # We call 'absolute()' rather than using 'os.getcwd()' directly to
+        # enable users to replace the implementation of 'absolute()' in a
+        # subclass and benefit from the new behaviour here. This works because
+        # os.path.abspath('.') == os.getcwd().
+        return cls().absolute()
+
+    @classmethod
+    def home(cls):
+        """Return a new path pointing to the user's home directory (as
+        returned by os.path.expanduser('~')).
+        """
+        return cls("~").expanduser()
+
     def absolute(self):
         """Return an absolute version of this path by prepending the current
         working directory. No normalization or symlink resolution is performed.
@@ -911,13 +1160,6 @@ def check_eloop(e):
                 check_eloop(e)
         return p
 
-    def stat(self, *, follow_symlinks=True):
-        """
-        Return the result of the stat() system call on this path, like
-        os.stat() does.
-        """
-        return os.stat(self, follow_symlinks=follow_symlinks)
-
     def owner(self):
         """
         Return the login name of the file owner.
@@ -939,51 +1181,6 @@ def group(self):
         except ImportError:
             raise NotImplementedError("Path.group() is unsupported on this system")
 
-    def open(self, mode='r', buffering=-1, encoding=None,
-             errors=None, newline=None):
-        """
-        Open the file pointed by this path and return a file object, as
-        the built-in open() function does.
-        """
-        if "b" not in mode:
-            encoding = io.text_encoding(encoding)
-        return io.open(self, mode, buffering, encoding, errors, newline)
-
-    def read_bytes(self):
-        """
-        Open the file in bytes mode, read it, and close the file.
-        """
-        with self.open(mode='rb') as f:
-            return f.read()
-
-    def read_text(self, encoding=None, errors=None):
-        """
-        Open the file in text mode, read it, and close the file.
-        """
-        encoding = io.text_encoding(encoding)
-        with self.open(mode='r', encoding=encoding, errors=errors) as f:
-            return f.read()
-
-    def write_bytes(self, data):
-        """
-        Open the file in bytes mode, write to it, and close the file.
-        """
-        # type-check for the buffer interface before truncating the file
-        view = memoryview(data)
-        with self.open(mode='wb') as f:
-            return f.write(view)
-
-    def write_text(self, data, encoding=None, errors=None, newline=None):
-        """
-        Open the file in text mode, write to it, and close the file.
-        """
-        if not isinstance(data, str):
-            raise TypeError('data must be str, not %s' %
-                            data.__class__.__name__)
-        encoding = io.text_encoding(encoding)
-        with self.open(mode='w', encoding=encoding, errors=errors, newline=newline) as f:
-            return f.write(data)
-
     def readlink(self):
         """
         Return the path to which the symbolic link points.
@@ -1061,13 +1258,6 @@ def rmdir(self):
         """
         os.rmdir(self)
 
-    def lstat(self):
-        """
-        Like stat(), except if the path points to a symlink, the symlink's
-        status information is returned, rather than its target's.
-        """
-        return self.stat(follow_symlinks=False)
-
     def rename(self, target):
         """
         Rename this path to the target path.
@@ -1113,151 +1303,6 @@ def hardlink_to(self, target):
             raise NotImplementedError("os.link() not available on this system")
         os.link(target, self)
 
-
-    # Convenience functions for querying the stat results
-
-    def exists(self, *, follow_symlinks=True):
-        """
-        Whether this path exists.
-
-        This method normally follows symlinks; to check whether a symlink exists,
-        add the argument follow_symlinks=False.
-        """
-        try:
-            self.stat(follow_symlinks=follow_symlinks)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-        return True
-
-    def is_dir(self):
-        """
-        Whether this path is a directory.
-        """
-        try:
-            return S_ISDIR(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_file(self):
-        """
-        Whether this path is a regular file (also True for symlinks pointing
-        to regular files).
-        """
-        try:
-            return S_ISREG(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_mount(self):
-        """
-        Check if this path is a mount point
-        """
-        return self._flavour.ismount(self)
-
-    def is_symlink(self):
-        """
-        Whether this path is a symbolic link.
-        """
-        try:
-            return S_ISLNK(self.lstat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_junction(self):
-        """
-        Whether this path is a junction.
-        """
-        return self._flavour.isjunction(self)
-
-    def is_block_device(self):
-        """
-        Whether this path is a block device.
-        """
-        try:
-            return S_ISBLK(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_char_device(self):
-        """
-        Whether this path is a character device.
-        """
-        try:
-            return S_ISCHR(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_fifo(self):
-        """
-        Whether this path is a FIFO.
-        """
-        try:
-            return S_ISFIFO(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
-    def is_socket(self):
-        """
-        Whether this path is a socket.
-        """
-        try:
-            return S_ISSOCK(self.stat().st_mode)
-        except OSError as e:
-            if not _ignore_error(e):
-                raise
-            # Path doesn't exist or is a broken symlink
-            # (see http://web.archive.org/web/20200623061726/https://bitbucket.org/pitrou/pathlib/issues/12/ )
-            return False
-        except ValueError:
-            # Non-encodable path
-            return False
-
     def expanduser(self):
         """ Return a new path with expanded ~ and ~user constructs
         (as returned by os.path.expanduser)
@@ -1272,51 +1317,6 @@ def expanduser(self):
 
         return self
 
-    def walk(self, top_down=True, on_error=None, follow_symlinks=False):
-        """Walk the directory tree from this directory, similar to os.walk()."""
-        sys.audit("pathlib.Path.walk", self, on_error, follow_symlinks)
-        paths = [self]
-
-        while paths:
-            path = paths.pop()
-            if isinstance(path, tuple):
-                yield path
-                continue
-
-            # We may not have read permission for self, in which case we can't
-            # get a list of the files the directory contains. os.walk()
-            # always suppressed the exception in that instance, rather than
-            # blow up for a minor reason when (say) a thousand readable
-            # directories are still left to visit. That logic is copied here.
-            try:
-                scandir_it = path._scandir()
-            except OSError as error:
-                if on_error is not None:
-                    on_error(error)
-                continue
-
-            with scandir_it:
-                dirnames = []
-                filenames = []
-                for entry in scandir_it:
-                    try:
-                        is_dir = entry.is_dir(follow_symlinks=follow_symlinks)
-                    except OSError:
-                        # Carried over from os.path.isdir().
-                        is_dir = False
-
-                    if is_dir:
-                        dirnames.append(entry.name)
-                    else:
-                        filenames.append(entry.name)
-
-            if top_down:
-                yield path, dirnames, filenames
-            else:
-                paths.append((path, dirnames, filenames))
-
-            paths += [path._make_child_relpath(d) for d in reversed(dirnames)]
-
 
 class PosixPath(Path, PurePosixPath):
     """Path subclass for non-Windows systems.

From 8d95012c95988dc517db6e09348aab996868699c Mon Sep 17 00:00:00 2001
From: Arthur Pastel <arthur.pastel@gmail.com>
Date: Sun, 7 May 2023 21:42:26 +0200
Subject: [PATCH 05/35] gh-103650: Fix perf maps address format (#103651)

---
 Lib/test/test_perf_profiler.py                       | 12 +++++++++---
 .../2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst   |  1 +
 Python/perf_trampoline.c                             |  2 +-
 3 files changed, 11 insertions(+), 4 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst

diff --git a/Lib/test/test_perf_profiler.py b/Lib/test/test_perf_profiler.py
index 2b977d78d39324..5418f9f35485f8 100644
--- a/Lib/test/test_perf_profiler.py
+++ b/Lib/test/test_perf_profiler.py
@@ -1,4 +1,5 @@
 import unittest
+import string
 import subprocess
 import sys
 import sysconfig
@@ -70,9 +71,14 @@ def baz():
         perf_file = pathlib.Path(f"/tmp/perf-{process.pid}.map")
         self.assertTrue(perf_file.exists())
         perf_file_contents = perf_file.read_text()
-        self.assertIn(f"py::foo:{script}", perf_file_contents)
-        self.assertIn(f"py::bar:{script}", perf_file_contents)
-        self.assertIn(f"py::baz:{script}", perf_file_contents)
+        perf_lines = perf_file_contents.splitlines();
+        expected_symbols = [f"py::foo:{script}", f"py::bar:{script}", f"py::baz:{script}"]
+        for expected_symbol in expected_symbols:
+            perf_line = next((line for line in perf_lines if expected_symbol in line), None)
+            self.assertIsNotNone(perf_line, f"Could not find {expected_symbol} in perf file")
+            perf_addr = perf_line.split(" ")[0]
+            self.assertFalse(perf_addr.startswith("0x"), "Address should not be prefixed with 0x")
+            self.assertTrue(set(perf_addr).issubset(string.hexdigits), "Address should contain only hex characters")
 
     def test_trampoline_works_with_forks(self):
         code = """if 1:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst
new file mode 100644
index 00000000000000..5434660e9d6ffb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-16-17-51.gh-issue-103650.K1MFXR.rst	
@@ -0,0 +1 @@
+Change the perf map format to remove the '0x' prefix from the addresses
diff --git a/Python/perf_trampoline.c b/Python/perf_trampoline.c
index 1957ab82c33951..3b183280e1f24c 100644
--- a/Python/perf_trampoline.c
+++ b/Python/perf_trampoline.c
@@ -253,7 +253,7 @@ perf_map_write_entry(void *state, const void *code_addr,
                                   NULL);
         return;
     }
-    fprintf(method_file, "%p %x py::%s:%s\n", code_addr, code_size, entry,
+    fprintf(method_file, "%" PRIxPTR " %x py::%s:%s\n", (uintptr_t) code_addr, code_size, entry,
             filename);
     fflush(method_file);
 }

From c0ece3dc9791694e960952ba74070efaaa79a676 Mon Sep 17 00:00:00 2001
From: Barney Gale <barney.gale@gmail.com>
Date: Sun, 7 May 2023 22:12:50 +0100
Subject: [PATCH 06/35] GH-102613: Improve performance of
 `pathlib.Path.rglob()` (GH-104244)

Stop de-duplicating results in `_RecursiveWildcardSelector`. A new
`_DoubleRecursiveWildcardSelector` class is introduced which performs
de-duplication, but this is used _only_ for patterns with multiple
non-adjacent `**` segments, such as `path.glob('**/foo/**')`. By avoiding
the use of a set, `PurePath.__hash__()` is not called, and so paths do not
need to be stringified and case-normalised.

Also merge adjacent '**' segments in patterns.
---
 Lib/pathlib.py                                | 54 +++++++++++++------
 Lib/test/test_pathlib.py                      |  6 ++-
 ...-05-06-20-37-46.gh-issue-102613.QZG9iX.rst |  3 ++
 3 files changed, 45 insertions(+), 18 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst

diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 68255aa3e511ec..20ec1ce9d80374 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -64,17 +64,25 @@ def _is_case_sensitive(flavour):
 @functools.lru_cache()
 def _make_selector(pattern_parts, flavour, case_sensitive):
     pat = pattern_parts[0]
-    child_parts = pattern_parts[1:]
     if not pat:
         return _TerminatingSelector()
     if pat == '**':
-        cls = _RecursiveWildcardSelector
-    elif pat == '..':
-        cls = _ParentSelector
-    elif '**' in pat:
-        raise ValueError("Invalid pattern: '**' can only be an entire path component")
+        child_parts_idx = 1
+        while child_parts_idx < len(pattern_parts) and pattern_parts[child_parts_idx] == '**':
+            child_parts_idx += 1
+        child_parts = pattern_parts[child_parts_idx:]
+        if '**' in child_parts:
+            cls = _DoubleRecursiveWildcardSelector
+        else:
+            cls = _RecursiveWildcardSelector
     else:
-        cls = _WildcardSelector
+        child_parts = pattern_parts[1:]
+        if pat == '..':
+            cls = _ParentSelector
+        elif '**' in pat:
+            raise ValueError("Invalid pattern: '**' can only be an entire path component")
+        else:
+            cls = _WildcardSelector
     return cls(pat, child_parts, flavour, case_sensitive)
 
 
@@ -183,20 +191,32 @@ def _iterate_directories(self, parent_path, scandir):
 
     def _select_from(self, parent_path, scandir):
         try:
-            yielded = set()
-            try:
-                successor_select = self.successor._select_from
-                for starting_point in self._iterate_directories(parent_path, scandir):
-                    for p in successor_select(starting_point, scandir):
-                        if p not in yielded:
-                            yield p
-                            yielded.add(p)
-            finally:
-                yielded.clear()
+            successor_select = self.successor._select_from
+            for starting_point in self._iterate_directories(parent_path, scandir):
+                for p in successor_select(starting_point, scandir):
+                    yield p
         except PermissionError:
             return
 
 
+class _DoubleRecursiveWildcardSelector(_RecursiveWildcardSelector):
+    """
+    Like _RecursiveWildcardSelector, but also de-duplicates results from
+    successive selectors. This is necessary if the pattern contains
+    multiple non-adjacent '**' segments.
+    """
+
+    def _select_from(self, parent_path, scandir):
+        yielded = set()
+        try:
+            for p in super()._select_from(parent_path, scandir):
+                if p not in yielded:
+                    yield p
+                    yielded.add(p)
+        finally:
+            yielded.clear()
+
+
 #
 # Public API
 #
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index e25c77f2ba8af6..ee0ef9a34c385c 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -1853,13 +1853,14 @@ def _check(path, pattern, case_sensitive, expected):
 
     def test_rglob_common(self):
         def _check(glob, expected):
-            self.assertEqual(set(glob), { P(BASE, q) for q in expected })
+            self.assertEqual(sorted(glob), sorted(P(BASE, q) for q in expected))
         P = self.cls
         p = P(BASE)
         it = p.rglob("fileA")
         self.assertIsInstance(it, collections.abc.Iterator)
         _check(it, ["fileA"])
         _check(p.rglob("fileB"), ["dirB/fileB"])
+        _check(p.rglob("**/fileB"), ["dirB/fileB"])
         _check(p.rglob("*/fileA"), [])
         if not os_helper.can_symlink():
             _check(p.rglob("*/fileB"), ["dirB/fileB"])
@@ -1883,9 +1884,12 @@ def _check(glob, expected):
         _check(p.rglob("*"), ["dirC/fileC", "dirC/novel.txt",
                               "dirC/dirD", "dirC/dirD/fileD"])
         _check(p.rglob("file*"), ["dirC/fileC", "dirC/dirD/fileD"])
+        _check(p.rglob("**/file*"), ["dirC/fileC", "dirC/dirD/fileD"])
+        _check(p.rglob("dir*/**"), ["dirC/dirD"])
         _check(p.rglob("*/*"), ["dirC/dirD/fileD"])
         _check(p.rglob("*/"), ["dirC/dirD"])
         _check(p.rglob(""), ["dirC", "dirC/dirD"])
+        _check(p.rglob("**"), ["dirC", "dirC/dirD"])
         # gh-91616, a re module regression
         _check(p.rglob("*.txt"), ["dirC/novel.txt"])
         _check(p.rglob("*.*"), ["dirC/novel.txt"])
diff --git a/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst b/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst
new file mode 100644
index 00000000000000..01f8b948d2cb65
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-06-20-37-46.gh-issue-102613.QZG9iX.rst
@@ -0,0 +1,3 @@
+Improve performance of :meth:`pathlib.Path.glob` when expanding recursive
+wildcards ("``**``") by merging adjacent wildcards and de-duplicating
+results only when necessary.

From 06c2a4858b8806abc700a0471434067910db54ec Mon Sep 17 00:00:00 2001
From: chgnrdv <52372310+chgnrdv@users.noreply.github.com>
Date: Mon, 8 May 2023 00:15:44 +0300
Subject: [PATCH 07/35] gh-104265 Disallow instantiation of `_csv.Reader` and
 `_csv.Writer` (#104266)

---
 Lib/test/test_csv.py                                     | 9 ++++++++-
 .../2023-05-07-19-56-45.gh-issue-104265.fVblry.rst       | 4 ++++
 Modules/_csv.c                                           | 4 ++--
 3 files changed, 14 insertions(+), 3 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst

diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 8fb97bc0c1a1a7..de7ac97d72cb8e 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -10,7 +10,7 @@
 import gc
 import pickle
 from test import support
-from test.support import warnings_helper
+from test.support import warnings_helper, import_helper, check_disallow_instantiation
 from itertools import permutations
 from textwrap import dedent
 from collections import OrderedDict
@@ -1430,5 +1430,12 @@ def test_subclassable(self):
         # issue 44089
         class Foo(csv.Error): ...
 
+    @support.cpython_only
+    def test_disallow_instantiation(self):
+        _csv = import_helper.import_module("_csv")
+        for tp in _csv.Reader, _csv.Writer:
+            with self.subTest(tp=tp):
+                check_disallow_instantiation(self, tp)
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst
new file mode 100644
index 00000000000000..9c582844bf909b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-07-19-56-45.gh-issue-104265.fVblry.rst
@@ -0,0 +1,4 @@
+Prevent possible crash by disallowing instantiation of the
+:class:`!_csv.Reader` and :class:`!_csv.Writer` types.
+The regression was introduced in 3.10.0a4 with PR 23224 (:issue:`14935`).
+Patch by Radislav Chugunov.
diff --git a/Modules/_csv.c b/Modules/_csv.c
index 0cde5c5a8bdc68..9ab2ad266c2739 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -1000,7 +1000,7 @@ PyType_Spec Reader_Type_spec = {
     .name = "_csv.reader",
     .basicsize = sizeof(ReaderObj),
     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
-              Py_TPFLAGS_IMMUTABLETYPE),
+              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
     .slots = Reader_Type_slots
 };
 
@@ -1431,7 +1431,7 @@ PyType_Spec Writer_Type_spec = {
     .name = "_csv.writer",
     .basicsize = sizeof(WriterObj),
     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
-              Py_TPFLAGS_IMMUTABLETYPE),
+              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
     .slots = Writer_Type_slots,
 };
 

From ac020624b32820e8e6e272122b94883f8e75ac61 Mon Sep 17 00:00:00 2001
From: "Erlend E. Aasland" <erlend.aasland@protonmail.com>
Date: Sun, 7 May 2023 23:55:37 +0200
Subject: [PATCH 08/35] gh-64660: Don't hardcode Argument Clinic return
 converter result variable name (#104200)

---
 Tools/clinic/clinic.py | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 704325670bc994..a6f330d1502dad 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -356,6 +356,7 @@ def __init__(self):
         # you should check the _return_value for errors, and
         # "goto exit" if there are any.
         self.return_conversion = []
+        self.converter_retval = "_return_value"
 
         # The C statements required to do some operations
         # after the end of parsing but before cleaning up.
@@ -3893,15 +3894,15 @@ def __init__(self, *, py_default=None, **kwargs):
     def return_converter_init(self):
         pass
 
-    def declare(self, data, name="_return_value"):
+    def declare(self, data):
         line = []
         add = line.append
         add(self.type)
         if not self.type.endswith('*'):
             add(' ')
-        add(name + ';')
+        add(data.converter_retval + ';')
         data.declarations.append(''.join(line))
-        data.return_value = name
+        data.return_value = data.converter_retval
 
     def err_occurred_if(self, expr, data):
         data.return_conversion.append('if (({}) && PyErr_Occurred()) {{\n    goto exit;\n}}\n'.format(expr))
@@ -3923,8 +3924,10 @@ class bool_return_converter(CReturnConverter):
 
     def render(self, function, data):
         self.declare(data)
-        self.err_occurred_if("_return_value == -1", data)
-        data.return_conversion.append('return_value = PyBool_FromLong((long)_return_value);\n')
+        self.err_occurred_if(f"{data.converter_retval} == -1", data)
+        data.return_conversion.append(
+            f'return_value = PyBool_FromLong((long){data.converter_retval});\n'
+        )
 
 class long_return_converter(CReturnConverter):
     type = 'long'
@@ -3934,9 +3937,10 @@ class long_return_converter(CReturnConverter):
 
     def render(self, function, data):
         self.declare(data)
-        self.err_occurred_if("_return_value == {}-1".format(self.unsigned_cast), data)
+        self.err_occurred_if(f"{data.converter_retval} == {self.unsigned_cast}-1", data)
         data.return_conversion.append(
-            ''.join(('return_value = ', self.conversion_fn, '(', self.cast, '_return_value);\n')))
+            f'return_value = {self.conversion_fn}({self.cast}{data.converter_retval});\n'
+        )
 
 class int_return_converter(long_return_converter):
     type = 'int'
@@ -3978,9 +3982,10 @@ class double_return_converter(CReturnConverter):
 
     def render(self, function, data):
         self.declare(data)
-        self.err_occurred_if("_return_value == -1.0", data)
+        self.err_occurred_if(f"{data.converter_retval} == -1.0", data)
         data.return_conversion.append(
-            'return_value = PyFloat_FromDouble(' + self.cast + '_return_value);\n')
+            f'return_value = PyFloat_FromDouble({self.cast}{data.converter_retval});\n'
+        )
 
 class float_return_converter(double_return_converter):
     type = 'float'

From 01cc9c1ff79bf18fe34c05c6cd573e79ff9487c3 Mon Sep 17 00:00:00 2001
From: Burak Saler <59198732+buraksaler@users.noreply.github.com>
Date: Mon, 8 May 2023 02:43:50 +0300
Subject: [PATCH 09/35] gh-104273: Remove redundant len() calls in argparse
 function (#104274)

---
 Lib/argparse.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/Lib/argparse.py b/Lib/argparse.py
index 68089a5c1e80b0..f5f44ff02c0d38 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -345,21 +345,22 @@ def _format_usage(self, usage, actions, groups, prefix):
                 def get_lines(parts, indent, prefix=None):
                     lines = []
                     line = []
+                    indent_length = len(indent)
                     if prefix is not None:
                         line_len = len(prefix) - 1
                     else:
-                        line_len = len(indent) - 1
+                        line_len = indent_length - 1
                     for part in parts:
                         if line_len + 1 + len(part) > text_width and line:
                             lines.append(indent + ' '.join(line))
                             line = []
-                            line_len = len(indent) - 1
+                            line_len = indent_length - 1
                         line.append(part)
                         line_len += len(part) + 1
                     if line:
                         lines.append(indent + ' '.join(line))
                     if prefix is not None:
-                        lines[0] = lines[0][len(indent):]
+                        lines[0] = lines[0][indent_length:]
                     return lines
 
                 # if prog is short, follow it with optionals or positionals

From 15665d896bae9c3d8b60bd7210ac1b7dc533b093 Mon Sep 17 00:00:00 2001
From: Jonathan Protzenko <protz@microsoft.com>
Date: Sun, 7 May 2023 20:50:04 -0700
Subject: [PATCH 10/35] gh-99108: Replace SHA3 implementation HACL* version
 (#103597)

Replaces our built-in SHA3 implementation with a verified one from the HACL* project.

This implementation is used when OpenSSL does not provide SHA3 or is not present.

3.11 shiped with a very slow tiny sha3 implementation to get off of the <=3.10 reference implementation that wound up having serious bugs. This brings us back to a reasonably performing built-in implementation consistent with what we've just replaced our other guaranteed available standard hash algorithms with: code from the HACL* project.

---------

Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
 Makefile.pre.in                               |   2 +-
 ...3-04-17-14-38-12.gh-issue-99108.720lG8.rst |   2 +
 Modules/Setup                                 |   2 +-
 Modules/Setup.stdlib.in                       |   2 +-
 Modules/_hacl/Hacl_Hash_SHA3.c                | 826 ++++++++++++++++++
 Modules/_hacl/Hacl_Hash_SHA3.h                | 136 +++
 Modules/_hacl/Hacl_Streaming_Types.h          |  17 +
 Modules/_hacl/include/krml/internal/target.h  |  44 +
 .../_hacl/include/krml/lowstar_endianness.h   |   5 +-
 Modules/_hacl/internal/Hacl_Hash_SHA3.h       |  65 ++
 Modules/_hacl/python_hacl_namespaces.h        |  23 +
 Modules/_hacl/refresh.sh                      |  11 +-
 Modules/_sha3/LICENSE                         |  22 -
 Modules/_sha3/README.txt                      |   8 -
 Modules/_sha3/sha3.c                          | 193 ----
 Modules/_sha3/sha3.h                          |  49 --
 Modules/{_sha3 => }/clinic/sha3module.c.h     |   4 +-
 Modules/{_sha3 => }/sha3module.c              | 191 ++--
 PCbuild/pythoncore.vcxproj                    |   9 +-
 PCbuild/pythoncore.vcxproj.filters            |  19 +-
 Tools/c-analyzer/cpython/_parser.py           |   8 +-
 21 files changed, 1204 insertions(+), 434 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst
 create mode 100644 Modules/_hacl/Hacl_Hash_SHA3.c
 create mode 100644 Modules/_hacl/Hacl_Hash_SHA3.h
 create mode 100644 Modules/_hacl/internal/Hacl_Hash_SHA3.h
 delete mode 100644 Modules/_sha3/LICENSE
 delete mode 100644 Modules/_sha3/README.txt
 delete mode 100644 Modules/_sha3/sha3.c
 delete mode 100644 Modules/_sha3/sha3.h
 rename Modules/{_sha3 => }/clinic/sha3module.c.h (98%)
 rename Modules/{_sha3 => }/sha3module.c (75%)

diff --git a/Makefile.pre.in b/Makefile.pre.in
index 736a520d0e8fb6..329466580b9cb0 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2698,7 +2698,7 @@ MODULE__IO_DEPS=$(srcdir)/Modules/_io/_iomodule.h
 MODULE__MD5_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_MD5.h Modules/_hacl/Hacl_Hash_MD5.c
 MODULE__SHA1_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_SHA1.h Modules/_hacl/Hacl_Hash_SHA1.c
 MODULE__SHA2_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_SHA2_HEADERS) $(LIBHACL_SHA2_A)
-MODULE__SHA3_DEPS=$(srcdir)/Modules/_sha3/sha3.c $(srcdir)/Modules/_sha3/sha3.h $(srcdir)/Modules/hashlib.h
+MODULE__SHA3_DEPS=$(srcdir)/Modules/hashlib.h $(LIBHACL_HEADERS) Modules/_hacl/Hacl_Hash_SHA3.h Modules/_hacl/Hacl_Hash_SHA3.c
 MODULE__SOCKET_DEPS=$(srcdir)/Modules/socketmodule.h $(srcdir)/Modules/addrinfo.h $(srcdir)/Modules/getaddrinfo.c $(srcdir)/Modules/getnameinfo.c
 MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir)/Modules/_ssl/debughelpers.c $(srcdir)/Modules/_ssl/misc.c $(srcdir)/Modules/_ssl_data.h $(srcdir)/Modules/_ssl_data_111.h $(srcdir)/Modules/_ssl_data_300.h $(srcdir)/Modules/socketmodule.h
 MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h
diff --git a/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst b/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst
new file mode 100644
index 00000000000000..f259acf753831c
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2023-04-17-14-38-12.gh-issue-99108.720lG8.rst
@@ -0,0 +1,2 @@
+Upgrade built-in :mod:`hashlib` SHA3 implementation to a verified implementation
+from the ``HACL*`` project.  Used when OpenSSL is not present or lacks SHA3.
diff --git a/Modules/Setup b/Modules/Setup
index 1c6f2f7ea5182d..e5bc078af62c41 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -166,7 +166,7 @@ PYTHONPATH=$(COREPYTHONPATH)
 #_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 #_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 #_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a
-#_sha3 _sha3/sha3module.c
+#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_sha3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 
 # text encodings and unicode
 #_codecs_cn cjkcodecs/_codecs_cn.c
diff --git a/Modules/Setup.stdlib.in b/Modules/Setup.stdlib.in
index a7803cf7c00e68..8e66576b5c5f00 100644
--- a/Modules/Setup.stdlib.in
+++ b/Modules/Setup.stdlib.in
@@ -80,7 +80,7 @@
 @MODULE__MD5_TRUE@_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 @MODULE__SHA1_TRUE@_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 @MODULE__SHA2_TRUE@_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a
-@MODULE__SHA3_TRUE@_sha3 _sha3/sha3module.c
+@MODULE__SHA3_TRUE@_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 @MODULE__BLAKE2_TRUE@_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c
 
 ############################################################################
diff --git a/Modules/_hacl/Hacl_Hash_SHA3.c b/Modules/_hacl/Hacl_Hash_SHA3.c
new file mode 100644
index 00000000000000..100afe7c2c6d1f
--- /dev/null
+++ b/Modules/_hacl/Hacl_Hash_SHA3.c
@@ -0,0 +1,826 @@
+/* MIT License
+ *
+ * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation
+ * Copyright (c) 2022-2023 HACL* Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#include "internal/Hacl_Hash_SHA3.h"
+
+static uint32_t block_len(Spec_Hash_Definitions_hash_alg a)
+{
+  switch (a)
+  {
+    case Spec_Hash_Definitions_SHA3_224:
+      {
+        return (uint32_t)144U;
+      }
+    case Spec_Hash_Definitions_SHA3_256:
+      {
+        return (uint32_t)136U;
+      }
+    case Spec_Hash_Definitions_SHA3_384:
+      {
+        return (uint32_t)104U;
+      }
+    case Spec_Hash_Definitions_SHA3_512:
+      {
+        return (uint32_t)72U;
+      }
+    case Spec_Hash_Definitions_Shake128:
+      {
+        return (uint32_t)168U;
+      }
+    case Spec_Hash_Definitions_Shake256:
+      {
+        return (uint32_t)136U;
+      }
+    default:
+      {
+        KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__);
+        KRML_HOST_EXIT(253U);
+      }
+  }
+}
+
+static uint32_t hash_len(Spec_Hash_Definitions_hash_alg a)
+{
+  switch (a)
+  {
+    case Spec_Hash_Definitions_SHA3_224:
+      {
+        return (uint32_t)28U;
+      }
+    case Spec_Hash_Definitions_SHA3_256:
+      {
+        return (uint32_t)32U;
+      }
+    case Spec_Hash_Definitions_SHA3_384:
+      {
+        return (uint32_t)48U;
+      }
+    case Spec_Hash_Definitions_SHA3_512:
+      {
+        return (uint32_t)64U;
+      }
+    default:
+      {
+        KRML_HOST_EPRINTF("KaRaMeL incomplete match at %s:%d\n", __FILE__, __LINE__);
+        KRML_HOST_EXIT(253U);
+      }
+  }
+}
+
+void
+Hacl_Hash_SHA3_update_multi_sha3(
+  Spec_Hash_Definitions_hash_alg a,
+  uint64_t *s,
+  uint8_t *blocks,
+  uint32_t n_blocks
+)
+{
+  for (uint32_t i = (uint32_t)0U; i < n_blocks; i++)
+  {
+    uint8_t *block = blocks + i * block_len(a);
+    Hacl_Impl_SHA3_absorb_inner(block_len(a), block, s);
+  }
+}
+
+void
+Hacl_Hash_SHA3_update_last_sha3(
+  Spec_Hash_Definitions_hash_alg a,
+  uint64_t *s,
+  uint8_t *input,
+  uint32_t input_len
+)
+{
+  uint8_t suffix;
+  if (a == Spec_Hash_Definitions_Shake128 || a == Spec_Hash_Definitions_Shake256)
+  {
+    suffix = (uint8_t)0x1fU;
+  }
+  else
+  {
+    suffix = (uint8_t)0x06U;
+  }
+  uint32_t len = block_len(a);
+  if (input_len == len)
+  {
+    Hacl_Impl_SHA3_absorb_inner(len, input, s);
+    uint8_t *uu____0 = input + input_len;
+    uint8_t lastBlock_[200U] = { 0U };
+    uint8_t *lastBlock = lastBlock_;
+    memcpy(lastBlock, uu____0, (uint32_t)0U * sizeof (uint8_t));
+    lastBlock[0U] = suffix;
+    Hacl_Impl_SHA3_loadState(len, lastBlock, s);
+    if (!((suffix & (uint8_t)0x80U) == (uint8_t)0U) && (uint32_t)0U == len - (uint32_t)1U)
+    {
+      Hacl_Impl_SHA3_state_permute(s);
+    }
+    uint8_t nextBlock_[200U] = { 0U };
+    uint8_t *nextBlock = nextBlock_;
+    nextBlock[len - (uint32_t)1U] = (uint8_t)0x80U;
+    Hacl_Impl_SHA3_loadState(len, nextBlock, s);
+    Hacl_Impl_SHA3_state_permute(s);
+    return;
+  }
+  uint8_t lastBlock_[200U] = { 0U };
+  uint8_t *lastBlock = lastBlock_;
+  memcpy(lastBlock, input, input_len * sizeof (uint8_t));
+  lastBlock[input_len] = suffix;
+  Hacl_Impl_SHA3_loadState(len, lastBlock, s);
+  if (!((suffix & (uint8_t)0x80U) == (uint8_t)0U) && input_len == len - (uint32_t)1U)
+  {
+    Hacl_Impl_SHA3_state_permute(s);
+  }
+  uint8_t nextBlock_[200U] = { 0U };
+  uint8_t *nextBlock = nextBlock_;
+  nextBlock[len - (uint32_t)1U] = (uint8_t)0x80U;
+  Hacl_Impl_SHA3_loadState(len, nextBlock, s);
+  Hacl_Impl_SHA3_state_permute(s);
+}
+
+typedef struct hash_buf2_s
+{
+  Hacl_Streaming_Keccak_hash_buf fst;
+  Hacl_Streaming_Keccak_hash_buf snd;
+}
+hash_buf2;
+
+Spec_Hash_Definitions_hash_alg Hacl_Streaming_Keccak_get_alg(Hacl_Streaming_Keccak_state *s)
+{
+  Hacl_Streaming_Keccak_state scrut = *s;
+  Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state;
+  return block_state.fst;
+}
+
+Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_hash_alg a)
+{
+  KRML_CHECK_SIZE(sizeof (uint8_t), block_len(a));
+  uint8_t *buf0 = (uint8_t *)KRML_HOST_CALLOC(block_len(a), sizeof (uint8_t));
+  uint64_t *buf = (uint64_t *)KRML_HOST_CALLOC((uint32_t)25U, sizeof (uint64_t));
+  Hacl_Streaming_Keccak_hash_buf block_state = { .fst = a, .snd = buf };
+  Hacl_Streaming_Keccak_state
+  s = { .block_state = block_state, .buf = buf0, .total_len = (uint64_t)(uint32_t)0U };
+  Hacl_Streaming_Keccak_state
+  *p = (Hacl_Streaming_Keccak_state *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_Keccak_state));
+  p[0U] = s;
+  uint64_t *s1 = block_state.snd;
+  for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i)
+    ((void **)s1)[_i] = (void *)(uint64_t)0U;
+  return p;
+}
+
+void Hacl_Streaming_Keccak_free(Hacl_Streaming_Keccak_state *s)
+{
+  Hacl_Streaming_Keccak_state scrut = *s;
+  uint8_t *buf = scrut.buf;
+  Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state;
+  uint64_t *s1 = block_state.snd;
+  KRML_HOST_FREE(s1);
+  KRML_HOST_FREE(buf);
+  KRML_HOST_FREE(s);
+}
+
+Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_copy(Hacl_Streaming_Keccak_state *s0)
+{
+  Hacl_Streaming_Keccak_state scrut0 = *s0;
+  Hacl_Streaming_Keccak_hash_buf block_state0 = scrut0.block_state;
+  uint8_t *buf0 = scrut0.buf;
+  uint64_t total_len0 = scrut0.total_len;
+  Spec_Hash_Definitions_hash_alg i = block_state0.fst;
+  KRML_CHECK_SIZE(sizeof (uint8_t), block_len(i));
+  uint8_t *buf1 = (uint8_t *)KRML_HOST_CALLOC(block_len(i), sizeof (uint8_t));
+  memcpy(buf1, buf0, block_len(i) * sizeof (uint8_t));
+  uint64_t *buf = (uint64_t *)KRML_HOST_CALLOC((uint32_t)25U, sizeof (uint64_t));
+  Hacl_Streaming_Keccak_hash_buf block_state = { .fst = i, .snd = buf };
+  hash_buf2 scrut = { .fst = block_state0, .snd = block_state };
+  uint64_t *s_dst = scrut.snd.snd;
+  uint64_t *s_src = scrut.fst.snd;
+  memcpy(s_dst, s_src, (uint32_t)25U * sizeof (uint64_t));
+  Hacl_Streaming_Keccak_state
+  s = { .block_state = block_state, .buf = buf1, .total_len = total_len0 };
+  Hacl_Streaming_Keccak_state
+  *p = (Hacl_Streaming_Keccak_state *)KRML_HOST_MALLOC(sizeof (Hacl_Streaming_Keccak_state));
+  p[0U] = s;
+  return p;
+}
+
+void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s)
+{
+  Hacl_Streaming_Keccak_state scrut = *s;
+  uint8_t *buf = scrut.buf;
+  Hacl_Streaming_Keccak_hash_buf block_state = scrut.block_state;
+  uint64_t *s1 = block_state.snd;
+  for (uint32_t _i = 0U; _i < (uint32_t)25U; ++_i)
+    ((void **)s1)[_i] = (void *)(uint64_t)0U;
+  Hacl_Streaming_Keccak_state
+  tmp = { .block_state = block_state, .buf = buf, .total_len = (uint64_t)(uint32_t)0U };
+  s[0U] = tmp;
+}
+
+uint32_t
+Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len)
+{
+  Hacl_Streaming_Keccak_state s = *p;
+  Hacl_Streaming_Keccak_hash_buf block_state = s.block_state;
+  uint64_t total_len = s.total_len;
+  Spec_Hash_Definitions_hash_alg i = block_state.fst;
+  if ((uint64_t)len > (uint64_t)0xffffffffU - total_len)
+  {
+    return (uint32_t)1U;
+  }
+  uint32_t sz;
+  if (total_len % (uint64_t)block_len(i) == (uint64_t)0U && total_len > (uint64_t)0U)
+  {
+    sz = block_len(i);
+  }
+  else
+  {
+    sz = (uint32_t)(total_len % (uint64_t)block_len(i));
+  }
+  if (len <= block_len(i) - sz)
+  {
+    Hacl_Streaming_Keccak_state s1 = *p;
+    Hacl_Streaming_Keccak_hash_buf block_state1 = s1.block_state;
+    uint8_t *buf = s1.buf;
+    uint64_t total_len1 = s1.total_len;
+    uint32_t sz1;
+    if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U)
+    {
+      sz1 = block_len(i);
+    }
+    else
+    {
+      sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i));
+    }
+    uint8_t *buf2 = buf + sz1;
+    memcpy(buf2, data, len * sizeof (uint8_t));
+    uint64_t total_len2 = total_len1 + (uint64_t)len;
+    *p
+    =
+      (
+        (Hacl_Streaming_Keccak_state){
+          .block_state = block_state1,
+          .buf = buf,
+          .total_len = total_len2
+        }
+      );
+  }
+  else if (sz == (uint32_t)0U)
+  {
+    Hacl_Streaming_Keccak_state s1 = *p;
+    Hacl_Streaming_Keccak_hash_buf block_state1 = s1.block_state;
+    uint8_t *buf = s1.buf;
+    uint64_t total_len1 = s1.total_len;
+    uint32_t sz1;
+    if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U)
+    {
+      sz1 = block_len(i);
+    }
+    else
+    {
+      sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i));
+    }
+    if (!(sz1 == (uint32_t)0U))
+    {
+      Spec_Hash_Definitions_hash_alg a1 = block_state1.fst;
+      uint64_t *s2 = block_state1.snd;
+      Hacl_Hash_SHA3_update_multi_sha3(a1, s2, buf, block_len(i) / block_len(a1));
+    }
+    uint32_t ite;
+    if ((uint64_t)len % (uint64_t)block_len(i) == (uint64_t)0U && (uint64_t)len > (uint64_t)0U)
+    {
+      ite = block_len(i);
+    }
+    else
+    {
+      ite = (uint32_t)((uint64_t)len % (uint64_t)block_len(i));
+    }
+    uint32_t n_blocks = (len - ite) / block_len(i);
+    uint32_t data1_len = n_blocks * block_len(i);
+    uint32_t data2_len = len - data1_len;
+    uint8_t *data1 = data;
+    uint8_t *data2 = data + data1_len;
+    Spec_Hash_Definitions_hash_alg a1 = block_state1.fst;
+    uint64_t *s2 = block_state1.snd;
+    Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data1, data1_len / block_len(a1));
+    uint8_t *dst = buf;
+    memcpy(dst, data2, data2_len * sizeof (uint8_t));
+    *p
+    =
+      (
+        (Hacl_Streaming_Keccak_state){
+          .block_state = block_state1,
+          .buf = buf,
+          .total_len = total_len1 + (uint64_t)len
+        }
+      );
+  }
+  else
+  {
+    uint32_t diff = block_len(i) - sz;
+    uint8_t *data1 = data;
+    uint8_t *data2 = data + diff;
+    Hacl_Streaming_Keccak_state s1 = *p;
+    Hacl_Streaming_Keccak_hash_buf block_state10 = s1.block_state;
+    uint8_t *buf0 = s1.buf;
+    uint64_t total_len10 = s1.total_len;
+    uint32_t sz10;
+    if (total_len10 % (uint64_t)block_len(i) == (uint64_t)0U && total_len10 > (uint64_t)0U)
+    {
+      sz10 = block_len(i);
+    }
+    else
+    {
+      sz10 = (uint32_t)(total_len10 % (uint64_t)block_len(i));
+    }
+    uint8_t *buf2 = buf0 + sz10;
+    memcpy(buf2, data1, diff * sizeof (uint8_t));
+    uint64_t total_len2 = total_len10 + (uint64_t)diff;
+    *p
+    =
+      (
+        (Hacl_Streaming_Keccak_state){
+          .block_state = block_state10,
+          .buf = buf0,
+          .total_len = total_len2
+        }
+      );
+    Hacl_Streaming_Keccak_state s10 = *p;
+    Hacl_Streaming_Keccak_hash_buf block_state1 = s10.block_state;
+    uint8_t *buf = s10.buf;
+    uint64_t total_len1 = s10.total_len;
+    uint32_t sz1;
+    if (total_len1 % (uint64_t)block_len(i) == (uint64_t)0U && total_len1 > (uint64_t)0U)
+    {
+      sz1 = block_len(i);
+    }
+    else
+    {
+      sz1 = (uint32_t)(total_len1 % (uint64_t)block_len(i));
+    }
+    if (!(sz1 == (uint32_t)0U))
+    {
+      Spec_Hash_Definitions_hash_alg a1 = block_state1.fst;
+      uint64_t *s2 = block_state1.snd;
+      Hacl_Hash_SHA3_update_multi_sha3(a1, s2, buf, block_len(i) / block_len(a1));
+    }
+    uint32_t ite;
+    if
+    (
+      (uint64_t)(len - diff)
+      % (uint64_t)block_len(i)
+      == (uint64_t)0U
+      && (uint64_t)(len - diff) > (uint64_t)0U
+    )
+    {
+      ite = block_len(i);
+    }
+    else
+    {
+      ite = (uint32_t)((uint64_t)(len - diff) % (uint64_t)block_len(i));
+    }
+    uint32_t n_blocks = (len - diff - ite) / block_len(i);
+    uint32_t data1_len = n_blocks * block_len(i);
+    uint32_t data2_len = len - diff - data1_len;
+    uint8_t *data11 = data2;
+    uint8_t *data21 = data2 + data1_len;
+    Spec_Hash_Definitions_hash_alg a1 = block_state1.fst;
+    uint64_t *s2 = block_state1.snd;
+    Hacl_Hash_SHA3_update_multi_sha3(a1, s2, data11, data1_len / block_len(a1));
+    uint8_t *dst = buf;
+    memcpy(dst, data21, data2_len * sizeof (uint8_t));
+    *p
+    =
+      (
+        (Hacl_Streaming_Keccak_state){
+          .block_state = block_state1,
+          .buf = buf,
+          .total_len = total_len1 + (uint64_t)(len - diff)
+        }
+      );
+  }
+  return (uint32_t)0U;
+}
+
+static void
+finish_(
+  Spec_Hash_Definitions_hash_alg a,
+  Hacl_Streaming_Keccak_state *p,
+  uint8_t *dst,
+  uint32_t l
+)
+{
+  Hacl_Streaming_Keccak_state scrut0 = *p;
+  Hacl_Streaming_Keccak_hash_buf block_state = scrut0.block_state;
+  uint8_t *buf_ = scrut0.buf;
+  uint64_t total_len = scrut0.total_len;
+  uint32_t r;
+  if (total_len % (uint64_t)block_len(a) == (uint64_t)0U && total_len > (uint64_t)0U)
+  {
+    r = block_len(a);
+  }
+  else
+  {
+    r = (uint32_t)(total_len % (uint64_t)block_len(a));
+  }
+  uint8_t *buf_1 = buf_;
+  uint64_t buf[25U] = { 0U };
+  Hacl_Streaming_Keccak_hash_buf tmp_block_state = { .fst = a, .snd = buf };
+  hash_buf2 scrut = { .fst = block_state, .snd = tmp_block_state };
+  uint64_t *s_dst = scrut.snd.snd;
+  uint64_t *s_src = scrut.fst.snd;
+  memcpy(s_dst, s_src, (uint32_t)25U * sizeof (uint64_t));
+  uint32_t ite0;
+  if (r % block_len(a) == (uint32_t)0U && r > (uint32_t)0U)
+  {
+    ite0 = block_len(a);
+  }
+  else
+  {
+    ite0 = r % block_len(a);
+  }
+  uint8_t *buf_last = buf_1 + r - ite0;
+  uint8_t *buf_multi = buf_1;
+  Spec_Hash_Definitions_hash_alg a1 = tmp_block_state.fst;
+  uint64_t *s0 = tmp_block_state.snd;
+  Hacl_Hash_SHA3_update_multi_sha3(a1, s0, buf_multi, (uint32_t)0U / block_len(a1));
+  Spec_Hash_Definitions_hash_alg a10 = tmp_block_state.fst;
+  uint64_t *s1 = tmp_block_state.snd;
+  Hacl_Hash_SHA3_update_last_sha3(a10, s1, buf_last, r);
+  Spec_Hash_Definitions_hash_alg a11 = tmp_block_state.fst;
+  uint64_t *s = tmp_block_state.snd;
+  if (a11 == Spec_Hash_Definitions_Shake128 || a11 == Spec_Hash_Definitions_Shake256)
+  {
+    uint32_t ite;
+    if (a11 == Spec_Hash_Definitions_Shake128 || a11 == Spec_Hash_Definitions_Shake256)
+    {
+      ite = l;
+    }
+    else
+    {
+      ite = hash_len(a11);
+    }
+    Hacl_Impl_SHA3_squeeze(s, block_len(a11), ite, dst);
+    return;
+  }
+  Hacl_Impl_SHA3_squeeze(s, block_len(a11), hash_len(a11), dst);
+}
+
+Hacl_Streaming_Keccak_error_code
+Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst)
+{
+  Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s);
+  if (a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256)
+  {
+    return Hacl_Streaming_Keccak_InvalidAlgorithm;
+  }
+  finish_(a1, s, dst, hash_len(a1));
+  return Hacl_Streaming_Keccak_Success;
+}
+
+Hacl_Streaming_Keccak_error_code
+Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l)
+{
+  Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s);
+  if (!(a1 == Spec_Hash_Definitions_Shake128 || a1 == Spec_Hash_Definitions_Shake256))
+  {
+    return Hacl_Streaming_Keccak_InvalidAlgorithm;
+  }
+  if (l == (uint32_t)0U)
+  {
+    return Hacl_Streaming_Keccak_InvalidLength;
+  }
+  finish_(a1, s, dst, l);
+  return Hacl_Streaming_Keccak_Success;
+}
+
+uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s)
+{
+  Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s);
+  return block_len(a1);
+}
+
+uint32_t Hacl_Streaming_Keccak_hash_len(Hacl_Streaming_Keccak_state *s)
+{
+  Spec_Hash_Definitions_hash_alg a1 = Hacl_Streaming_Keccak_get_alg(s);
+  return hash_len(a1);
+}
+
+bool Hacl_Streaming_Keccak_is_shake(Hacl_Streaming_Keccak_state *s)
+{
+  Spec_Hash_Definitions_hash_alg uu____0 = Hacl_Streaming_Keccak_get_alg(s);
+  return uu____0 == Spec_Hash_Definitions_Shake128 || uu____0 == Spec_Hash_Definitions_Shake256;
+}
+
+void
+Hacl_SHA3_shake128_hacl(
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint32_t outputByteLen,
+  uint8_t *output
+)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)1344U,
+    (uint32_t)256U,
+    inputByteLen,
+    input,
+    (uint8_t)0x1FU,
+    outputByteLen,
+    output);
+}
+
+void
+Hacl_SHA3_shake256_hacl(
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint32_t outputByteLen,
+  uint8_t *output
+)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)1088U,
+    (uint32_t)512U,
+    inputByteLen,
+    input,
+    (uint8_t)0x1FU,
+    outputByteLen,
+    output);
+}
+
+void Hacl_SHA3_sha3_224(uint32_t inputByteLen, uint8_t *input, uint8_t *output)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)1152U,
+    (uint32_t)448U,
+    inputByteLen,
+    input,
+    (uint8_t)0x06U,
+    (uint32_t)28U,
+    output);
+}
+
+void Hacl_SHA3_sha3_256(uint32_t inputByteLen, uint8_t *input, uint8_t *output)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)1088U,
+    (uint32_t)512U,
+    inputByteLen,
+    input,
+    (uint8_t)0x06U,
+    (uint32_t)32U,
+    output);
+}
+
+void Hacl_SHA3_sha3_384(uint32_t inputByteLen, uint8_t *input, uint8_t *output)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)832U,
+    (uint32_t)768U,
+    inputByteLen,
+    input,
+    (uint8_t)0x06U,
+    (uint32_t)48U,
+    output);
+}
+
+void Hacl_SHA3_sha3_512(uint32_t inputByteLen, uint8_t *input, uint8_t *output)
+{
+  Hacl_Impl_SHA3_keccak((uint32_t)576U,
+    (uint32_t)1024U,
+    inputByteLen,
+    input,
+    (uint8_t)0x06U,
+    (uint32_t)64U,
+    output);
+}
+
+static const
+uint32_t
+keccak_rotc[24U] =
+  {
+    (uint32_t)1U, (uint32_t)3U, (uint32_t)6U, (uint32_t)10U, (uint32_t)15U, (uint32_t)21U,
+    (uint32_t)28U, (uint32_t)36U, (uint32_t)45U, (uint32_t)55U, (uint32_t)2U, (uint32_t)14U,
+    (uint32_t)27U, (uint32_t)41U, (uint32_t)56U, (uint32_t)8U, (uint32_t)25U, (uint32_t)43U,
+    (uint32_t)62U, (uint32_t)18U, (uint32_t)39U, (uint32_t)61U, (uint32_t)20U, (uint32_t)44U
+  };
+
+static const
+uint32_t
+keccak_piln[24U] =
+  {
+    (uint32_t)10U, (uint32_t)7U, (uint32_t)11U, (uint32_t)17U, (uint32_t)18U, (uint32_t)3U,
+    (uint32_t)5U, (uint32_t)16U, (uint32_t)8U, (uint32_t)21U, (uint32_t)24U, (uint32_t)4U,
+    (uint32_t)15U, (uint32_t)23U, (uint32_t)19U, (uint32_t)13U, (uint32_t)12U, (uint32_t)2U,
+    (uint32_t)20U, (uint32_t)14U, (uint32_t)22U, (uint32_t)9U, (uint32_t)6U, (uint32_t)1U
+  };
+
+static const
+uint64_t
+keccak_rndc[24U] =
+  {
+    (uint64_t)0x0000000000000001U, (uint64_t)0x0000000000008082U, (uint64_t)0x800000000000808aU,
+    (uint64_t)0x8000000080008000U, (uint64_t)0x000000000000808bU, (uint64_t)0x0000000080000001U,
+    (uint64_t)0x8000000080008081U, (uint64_t)0x8000000000008009U, (uint64_t)0x000000000000008aU,
+    (uint64_t)0x0000000000000088U, (uint64_t)0x0000000080008009U, (uint64_t)0x000000008000000aU,
+    (uint64_t)0x000000008000808bU, (uint64_t)0x800000000000008bU, (uint64_t)0x8000000000008089U,
+    (uint64_t)0x8000000000008003U, (uint64_t)0x8000000000008002U, (uint64_t)0x8000000000000080U,
+    (uint64_t)0x000000000000800aU, (uint64_t)0x800000008000000aU, (uint64_t)0x8000000080008081U,
+    (uint64_t)0x8000000000008080U, (uint64_t)0x0000000080000001U, (uint64_t)0x8000000080008008U
+  };
+
+void Hacl_Impl_SHA3_state_permute(uint64_t *s)
+{
+  for (uint32_t i0 = (uint32_t)0U; i0 < (uint32_t)24U; i0++)
+  {
+    uint64_t _C[5U] = { 0U };
+    KRML_MAYBE_FOR5(i,
+      (uint32_t)0U,
+      (uint32_t)5U,
+      (uint32_t)1U,
+      _C[i] =
+        s[i
+        + (uint32_t)0U]
+        ^
+          (s[i
+          + (uint32_t)5U]
+          ^ (s[i + (uint32_t)10U] ^ (s[i + (uint32_t)15U] ^ s[i + (uint32_t)20U]))););
+    KRML_MAYBE_FOR5(i1,
+      (uint32_t)0U,
+      (uint32_t)5U,
+      (uint32_t)1U,
+      uint64_t uu____0 = _C[(i1 + (uint32_t)1U) % (uint32_t)5U];
+      uint64_t
+      _D =
+        _C[(i1 + (uint32_t)4U)
+        % (uint32_t)5U]
+        ^ (uu____0 << (uint32_t)1U | uu____0 >> (uint32_t)63U);
+      KRML_MAYBE_FOR5(i,
+        (uint32_t)0U,
+        (uint32_t)5U,
+        (uint32_t)1U,
+        s[i1 + (uint32_t)5U * i] = s[i1 + (uint32_t)5U * i] ^ _D;););
+    uint64_t x = s[1U];
+    uint64_t current = x;
+    for (uint32_t i = (uint32_t)0U; i < (uint32_t)24U; i++)
+    {
+      uint32_t _Y = keccak_piln[i];
+      uint32_t r = keccak_rotc[i];
+      uint64_t temp = s[_Y];
+      uint64_t uu____1 = current;
+      s[_Y] = uu____1 << r | uu____1 >> ((uint32_t)64U - r);
+      current = temp;
+    }
+    KRML_MAYBE_FOR5(i,
+      (uint32_t)0U,
+      (uint32_t)5U,
+      (uint32_t)1U,
+      uint64_t
+      v0 =
+        s[(uint32_t)0U
+        + (uint32_t)5U * i]
+        ^ (~s[(uint32_t)1U + (uint32_t)5U * i] & s[(uint32_t)2U + (uint32_t)5U * i]);
+      uint64_t
+      v1 =
+        s[(uint32_t)1U
+        + (uint32_t)5U * i]
+        ^ (~s[(uint32_t)2U + (uint32_t)5U * i] & s[(uint32_t)3U + (uint32_t)5U * i]);
+      uint64_t
+      v2 =
+        s[(uint32_t)2U
+        + (uint32_t)5U * i]
+        ^ (~s[(uint32_t)3U + (uint32_t)5U * i] & s[(uint32_t)4U + (uint32_t)5U * i]);
+      uint64_t
+      v3 =
+        s[(uint32_t)3U
+        + (uint32_t)5U * i]
+        ^ (~s[(uint32_t)4U + (uint32_t)5U * i] & s[(uint32_t)0U + (uint32_t)5U * i]);
+      uint64_t
+      v4 =
+        s[(uint32_t)4U
+        + (uint32_t)5U * i]
+        ^ (~s[(uint32_t)0U + (uint32_t)5U * i] & s[(uint32_t)1U + (uint32_t)5U * i]);
+      s[(uint32_t)0U + (uint32_t)5U * i] = v0;
+      s[(uint32_t)1U + (uint32_t)5U * i] = v1;
+      s[(uint32_t)2U + (uint32_t)5U * i] = v2;
+      s[(uint32_t)3U + (uint32_t)5U * i] = v3;
+      s[(uint32_t)4U + (uint32_t)5U * i] = v4;);
+    uint64_t c = keccak_rndc[i0];
+    s[0U] = s[0U] ^ c;
+  }
+}
+
+void Hacl_Impl_SHA3_loadState(uint32_t rateInBytes, uint8_t *input, uint64_t *s)
+{
+  uint8_t block[200U] = { 0U };
+  memcpy(block, input, rateInBytes * sizeof (uint8_t));
+  for (uint32_t i = (uint32_t)0U; i < (uint32_t)25U; i++)
+  {
+    uint64_t u = load64_le(block + i * (uint32_t)8U);
+    uint64_t x = u;
+    s[i] = s[i] ^ x;
+  }
+}
+
+static void storeState(uint32_t rateInBytes, uint64_t *s, uint8_t *res)
+{
+  uint8_t block[200U] = { 0U };
+  for (uint32_t i = (uint32_t)0U; i < (uint32_t)25U; i++)
+  {
+    uint64_t sj = s[i];
+    store64_le(block + i * (uint32_t)8U, sj);
+  }
+  memcpy(res, block, rateInBytes * sizeof (uint8_t));
+}
+
+void Hacl_Impl_SHA3_absorb_inner(uint32_t rateInBytes, uint8_t *block, uint64_t *s)
+{
+  Hacl_Impl_SHA3_loadState(rateInBytes, block, s);
+  Hacl_Impl_SHA3_state_permute(s);
+}
+
+static void
+absorb(
+  uint64_t *s,
+  uint32_t rateInBytes,
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint8_t delimitedSuffix
+)
+{
+  uint32_t n_blocks = inputByteLen / rateInBytes;
+  uint32_t rem = inputByteLen % rateInBytes;
+  for (uint32_t i = (uint32_t)0U; i < n_blocks; i++)
+  {
+    uint8_t *block = input + i * rateInBytes;
+    Hacl_Impl_SHA3_absorb_inner(rateInBytes, block, s);
+  }
+  uint8_t *last = input + n_blocks * rateInBytes;
+  uint8_t lastBlock_[200U] = { 0U };
+  uint8_t *lastBlock = lastBlock_;
+  memcpy(lastBlock, last, rem * sizeof (uint8_t));
+  lastBlock[rem] = delimitedSuffix;
+  Hacl_Impl_SHA3_loadState(rateInBytes, lastBlock, s);
+  if (!((delimitedSuffix & (uint8_t)0x80U) == (uint8_t)0U) && rem == rateInBytes - (uint32_t)1U)
+  {
+    Hacl_Impl_SHA3_state_permute(s);
+  }
+  uint8_t nextBlock_[200U] = { 0U };
+  uint8_t *nextBlock = nextBlock_;
+  nextBlock[rateInBytes - (uint32_t)1U] = (uint8_t)0x80U;
+  Hacl_Impl_SHA3_loadState(rateInBytes, nextBlock, s);
+  Hacl_Impl_SHA3_state_permute(s);
+}
+
+void
+Hacl_Impl_SHA3_squeeze(
+  uint64_t *s,
+  uint32_t rateInBytes,
+  uint32_t outputByteLen,
+  uint8_t *output
+)
+{
+  uint32_t outBlocks = outputByteLen / rateInBytes;
+  uint32_t remOut = outputByteLen % rateInBytes;
+  uint8_t *last = output + outputByteLen - remOut;
+  uint8_t *blocks = output;
+  for (uint32_t i = (uint32_t)0U; i < outBlocks; i++)
+  {
+    storeState(rateInBytes, s, blocks + i * rateInBytes);
+    Hacl_Impl_SHA3_state_permute(s);
+  }
+  storeState(remOut, s, last);
+}
+
+void
+Hacl_Impl_SHA3_keccak(
+  uint32_t rate,
+  uint32_t capacity,
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint8_t delimitedSuffix,
+  uint32_t outputByteLen,
+  uint8_t *output
+)
+{
+  uint32_t rateInBytes = rate / (uint32_t)8U;
+  uint64_t s[25U] = { 0U };
+  absorb(s, rateInBytes, inputByteLen, input, delimitedSuffix);
+  Hacl_Impl_SHA3_squeeze(s, rateInBytes, outputByteLen, output);
+}
+
diff --git a/Modules/_hacl/Hacl_Hash_SHA3.h b/Modules/_hacl/Hacl_Hash_SHA3.h
new file mode 100644
index 00000000000000..2a5cf4b1844b9d
--- /dev/null
+++ b/Modules/_hacl/Hacl_Hash_SHA3.h
@@ -0,0 +1,136 @@
+/* MIT License
+ *
+ * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation
+ * Copyright (c) 2022-2023 HACL* Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#ifndef __Hacl_Hash_SHA3_H
+#define __Hacl_Hash_SHA3_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <string.h>
+#include "krml/types.h"
+#include "krml/lowstar_endianness.h"
+#include "krml/internal/target.h"
+
+#include "Hacl_Streaming_Types.h"
+
+typedef struct Hacl_Streaming_Keccak_hash_buf_s
+{
+  Spec_Hash_Definitions_hash_alg fst;
+  uint64_t *snd;
+}
+Hacl_Streaming_Keccak_hash_buf;
+
+typedef struct Hacl_Streaming_Keccak_state_s
+{
+  Hacl_Streaming_Keccak_hash_buf block_state;
+  uint8_t *buf;
+  uint64_t total_len;
+}
+Hacl_Streaming_Keccak_state;
+
+Spec_Hash_Definitions_hash_alg Hacl_Streaming_Keccak_get_alg(Hacl_Streaming_Keccak_state *s);
+
+Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_hash_alg a);
+
+void Hacl_Streaming_Keccak_free(Hacl_Streaming_Keccak_state *s);
+
+Hacl_Streaming_Keccak_state *Hacl_Streaming_Keccak_copy(Hacl_Streaming_Keccak_state *s0);
+
+void Hacl_Streaming_Keccak_reset(Hacl_Streaming_Keccak_state *s);
+
+uint32_t
+Hacl_Streaming_Keccak_update(Hacl_Streaming_Keccak_state *p, uint8_t *data, uint32_t len);
+
+#define Hacl_Streaming_Keccak_Success 0
+#define Hacl_Streaming_Keccak_InvalidAlgorithm 1
+#define Hacl_Streaming_Keccak_InvalidLength 2
+
+typedef uint8_t Hacl_Streaming_Keccak_error_code;
+
+Hacl_Streaming_Keccak_error_code
+Hacl_Streaming_Keccak_finish(Hacl_Streaming_Keccak_state *s, uint8_t *dst);
+
+Hacl_Streaming_Keccak_error_code
+Hacl_Streaming_Keccak_squeeze(Hacl_Streaming_Keccak_state *s, uint8_t *dst, uint32_t l);
+
+uint32_t Hacl_Streaming_Keccak_block_len(Hacl_Streaming_Keccak_state *s);
+
+uint32_t Hacl_Streaming_Keccak_hash_len(Hacl_Streaming_Keccak_state *s);
+
+bool Hacl_Streaming_Keccak_is_shake(Hacl_Streaming_Keccak_state *s);
+
+void
+Hacl_SHA3_shake128_hacl(
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint32_t outputByteLen,
+  uint8_t *output
+);
+
+void
+Hacl_SHA3_shake256_hacl(
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint32_t outputByteLen,
+  uint8_t *output
+);
+
+void Hacl_SHA3_sha3_224(uint32_t inputByteLen, uint8_t *input, uint8_t *output);
+
+void Hacl_SHA3_sha3_256(uint32_t inputByteLen, uint8_t *input, uint8_t *output);
+
+void Hacl_SHA3_sha3_384(uint32_t inputByteLen, uint8_t *input, uint8_t *output);
+
+void Hacl_SHA3_sha3_512(uint32_t inputByteLen, uint8_t *input, uint8_t *output);
+
+void Hacl_Impl_SHA3_absorb_inner(uint32_t rateInBytes, uint8_t *block, uint64_t *s);
+
+void
+Hacl_Impl_SHA3_squeeze(
+  uint64_t *s,
+  uint32_t rateInBytes,
+  uint32_t outputByteLen,
+  uint8_t *output
+);
+
+void
+Hacl_Impl_SHA3_keccak(
+  uint32_t rate,
+  uint32_t capacity,
+  uint32_t inputByteLen,
+  uint8_t *input,
+  uint8_t delimitedSuffix,
+  uint32_t outputByteLen,
+  uint8_t *output
+);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#define __Hacl_Hash_SHA3_H_DEFINED
+#endif
diff --git a/Modules/_hacl/Hacl_Streaming_Types.h b/Modules/_hacl/Hacl_Streaming_Types.h
index 51057611ca978d..8a60b707bc4958 100644
--- a/Modules/_hacl/Hacl_Streaming_Types.h
+++ b/Modules/_hacl/Hacl_Streaming_Types.h
@@ -35,6 +35,23 @@ extern "C" {
 #include "krml/lowstar_endianness.h"
 #include "krml/internal/target.h"
 
+#define Spec_Hash_Definitions_SHA2_224 0
+#define Spec_Hash_Definitions_SHA2_256 1
+#define Spec_Hash_Definitions_SHA2_384 2
+#define Spec_Hash_Definitions_SHA2_512 3
+#define Spec_Hash_Definitions_SHA1 4
+#define Spec_Hash_Definitions_MD5 5
+#define Spec_Hash_Definitions_Blake2S 6
+#define Spec_Hash_Definitions_Blake2B 7
+#define Spec_Hash_Definitions_SHA3_256 8
+#define Spec_Hash_Definitions_SHA3_224 9
+#define Spec_Hash_Definitions_SHA3_384 10
+#define Spec_Hash_Definitions_SHA3_512 11
+#define Spec_Hash_Definitions_Shake128 12
+#define Spec_Hash_Definitions_Shake256 13
+
+typedef uint8_t Spec_Hash_Definitions_hash_alg;
+
 typedef struct Hacl_Streaming_MD_state_32_s
 {
   uint32_t *block_state;
diff --git a/Modules/_hacl/include/krml/internal/target.h b/Modules/_hacl/include/krml/internal/target.h
index dcbe7007b17be8..5a2f94eb2ec8da 100644
--- a/Modules/_hacl/include/krml/internal/target.h
+++ b/Modules/_hacl/include/krml/internal/target.h
@@ -19,6 +19,28 @@
 #  define inline __inline__
 #endif
 
+/******************************************************************************/
+/* Macros that KaRaMeL will generate.                                         */
+/******************************************************************************/
+
+/* For "bare" targets that do not have a C stdlib, the user might want to use
+ * [-add-early-include '"mydefinitions.h"'] and override these. */
+#ifndef KRML_HOST_PRINTF
+#  define KRML_HOST_PRINTF printf
+#endif
+
+#if (                                                                          \
+    (defined __STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&             \
+    (!(defined KRML_HOST_EPRINTF)))
+#  define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__)
+#elif !(defined KRML_HOST_EPRINTF) && defined(_MSC_VER)
+#  define KRML_HOST_EPRINTF(...) fprintf(stderr, __VA_ARGS__)
+#endif
+
+#ifndef KRML_HOST_EXIT
+#  define KRML_HOST_EXIT exit
+#endif
+
 #ifndef KRML_HOST_MALLOC
 #  define KRML_HOST_MALLOC malloc
 #endif
@@ -35,6 +57,28 @@
 #  define KRML_HOST_IGNORE(x) (void)(x)
 #endif
 
+/* In FStar.Buffer.fst, the size of arrays is uint32_t, but it's a number of
+ * *elements*. Do an ugly, run-time check (some of which KaRaMeL can eliminate).
+ */
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
+#  define _KRML_CHECK_SIZE_PRAGMA                                              \
+    _Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
+#else
+#  define _KRML_CHECK_SIZE_PRAGMA
+#endif
+
+#define KRML_CHECK_SIZE(size_elt, sz)                                          \
+  do {                                                                         \
+    _KRML_CHECK_SIZE_PRAGMA                                                    \
+    if (((size_t)(sz)) > ((size_t)(SIZE_MAX / (size_elt)))) {                  \
+      KRML_HOST_PRINTF(                                                        \
+          "Maximum allocatable size exceeded, aborting before overflow at "    \
+          "%s:%d\n",                                                           \
+          __FILE__, __LINE__);                                                 \
+      KRML_HOST_EXIT(253);                                                     \
+    }                                                                          \
+  } while (0)
+
 /* Macros for prettier unrolling of loops */
 #define KRML_LOOP1(i, n, x) { \
   x \
diff --git a/Modules/_hacl/include/krml/lowstar_endianness.h b/Modules/_hacl/include/krml/lowstar_endianness.h
index 32a7391e817ebb..1aa2ccd644c06f 100644
--- a/Modules/_hacl/include/krml/lowstar_endianness.h
+++ b/Modules/_hacl/include/krml/lowstar_endianness.h
@@ -77,7 +77,7 @@
 #  define le64toh(x) (x)
 
 /* ... for Windows (GCC-like, e.g. mingw or clang) */
-#elif (defined(_WIN32) || defined(_WIN64)) &&                                  \
+#elif (defined(_WIN32) || defined(_WIN64) || defined(__EMSCRIPTEN__)) &&       \
     (defined(__GNUC__) || defined(__clang__))
 
 #  define htobe16(x) __builtin_bswap16(x)
@@ -96,7 +96,8 @@
 #  define le64toh(x) (x)
 
 /* ... generic big-endian fallback code */
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+/* ... AIX doesn't have __BYTE_ORDER__ (with XLC compiler) & is always big-endian */
+#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(_AIX)
 
 /* byte swapping code inspired by:
  * https://github.com/rweather/arduinolibs/blob/master/libraries/Crypto/utility/EndianUtil.h
diff --git a/Modules/_hacl/internal/Hacl_Hash_SHA3.h b/Modules/_hacl/internal/Hacl_Hash_SHA3.h
new file mode 100644
index 00000000000000..1c9808b8dd497c
--- /dev/null
+++ b/Modules/_hacl/internal/Hacl_Hash_SHA3.h
@@ -0,0 +1,65 @@
+/* MIT License
+ *
+ * Copyright (c) 2016-2022 INRIA, CMU and Microsoft Corporation
+ * Copyright (c) 2022-2023 HACL* Contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#ifndef __internal_Hacl_Hash_SHA3_H
+#define __internal_Hacl_Hash_SHA3_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <string.h>
+#include "krml/types.h"
+#include "krml/lowstar_endianness.h"
+#include "krml/internal/target.h"
+
+#include "../Hacl_Hash_SHA3.h"
+
+void
+Hacl_Hash_SHA3_update_multi_sha3(
+  Spec_Hash_Definitions_hash_alg a,
+  uint64_t *s,
+  uint8_t *blocks,
+  uint32_t n_blocks
+);
+
+void
+Hacl_Hash_SHA3_update_last_sha3(
+  Spec_Hash_Definitions_hash_alg a,
+  uint64_t *s,
+  uint8_t *input,
+  uint32_t input_len
+);
+
+void Hacl_Impl_SHA3_state_permute(uint64_t *s);
+
+void Hacl_Impl_SHA3_loadState(uint32_t rateInBytes, uint8_t *input, uint64_t *s);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#define __internal_Hacl_Hash_SHA3_H_DEFINED
+#endif
diff --git a/Modules/_hacl/python_hacl_namespaces.h b/Modules/_hacl/python_hacl_namespaces.h
index ee28f244266b85..0df236282ac509 100644
--- a/Modules/_hacl/python_hacl_namespaces.h
+++ b/Modules/_hacl/python_hacl_namespaces.h
@@ -59,5 +59,28 @@
 #define Hacl_Streaming_SHA1_legacy_copy python_hashlib_Hacl_Streaming_SHA1_legacy_copy
 #define Hacl_Streaming_SHA1_legacy_hash python_hashlib_Hacl_Streaming_SHA1_legacy_hash
 
+#define Hacl_Hash_SHA3_update_last_sha3 python_hashlib_Hacl_Hash_SHA3_update_last_sha3
+#define Hacl_Hash_SHA3_update_multi_sha3 python_hashlib_Hacl_Hash_SHA3_update_multi_sha3
+#define Hacl_Impl_SHA3_absorb_inner python_hashlib_Hacl_Impl_SHA3_absorb_inner
+#define Hacl_Impl_SHA3_keccak python_hashlib_Hacl_Impl_SHA3_keccak
+#define Hacl_Impl_SHA3_loadState python_hashlib_Hacl_Impl_SHA3_loadState
+#define Hacl_Impl_SHA3_squeeze python_hashlib_Hacl_Impl_SHA3_squeeze
+#define Hacl_Impl_SHA3_state_permute python_hashlib_Hacl_Impl_SHA3_state_permute
+#define Hacl_SHA3_sha3_224 python_hashlib_Hacl_SHA3_sha3_224
+#define Hacl_SHA3_sha3_256 python_hashlib_Hacl_SHA3_sha3_256
+#define Hacl_SHA3_sha3_384 python_hashlib_Hacl_SHA3_sha3_384
+#define Hacl_SHA3_sha3_512 python_hashlib_Hacl_SHA3_sha3_512
+#define Hacl_SHA3_shake128_hacl python_hashlib_Hacl_SHA3_shake128_hacl
+#define Hacl_SHA3_shake256_hacl python_hashlib_Hacl_SHA3_shake256_hacl
+#define Hacl_Streaming_Keccak_block_len python_hashlib_Hacl_Streaming_Keccak_block_len
+#define Hacl_Streaming_Keccak_copy python_hashlib_Hacl_Streaming_Keccak_copy
+#define Hacl_Streaming_Keccak_finish python_hashlib_Hacl_Streaming_Keccak_finish
+#define Hacl_Streaming_Keccak_free python_hashlib_Hacl_Streaming_Keccak_free
+#define Hacl_Streaming_Keccak_get_alg python_hashlib_Hacl_Streaming_Keccak_get_alg
+#define Hacl_Streaming_Keccak_hash_len python_hashlib_Hacl_Streaming_Keccak_hash_len
+#define Hacl_Streaming_Keccak_is_shake python_hashlib_Hacl_Streaming_Keccak_is_shake
+#define Hacl_Streaming_Keccak_malloc python_hashlib_Hacl_Streaming_Keccak_malloc
+#define Hacl_Streaming_Keccak_reset python_hashlib_Hacl_Streaming_Keccak_reset
+#define Hacl_Streaming_Keccak_update python_hashlib_Hacl_Streaming_Keccak_update
 
 #endif  // _PYTHON_HACL_NAMESPACES_H
diff --git a/Modules/_hacl/refresh.sh b/Modules/_hacl/refresh.sh
index 76b92ec4599102..220ebbe5561341 100755
--- a/Modules/_hacl/refresh.sh
+++ b/Modules/_hacl/refresh.sh
@@ -22,7 +22,7 @@ fi
 
 # Update this when updating to a new version after verifying that the changes
 # the update brings in are good.
-expected_hacl_star_rev=13e0c6721ac9206c4249ecc1dc04ed617ad1e262
+expected_hacl_star_rev=363eae2c2eb60e46f182ddd4bd1cd3f1d00b35c9
 
 hacl_dir="$(realpath "$1")"
 cd "$(dirname "$0")"
@@ -45,11 +45,14 @@ dist_files=(
   Hacl_Hash_SHA1.h
   internal/Hacl_Hash_SHA1.h
   Hacl_Hash_MD5.h
+  Hacl_Hash_SHA3.h
   internal/Hacl_Hash_MD5.h
+  internal/Hacl_Hash_SHA3.h
   internal/Hacl_SHA2_Generic.h
   Hacl_Streaming_SHA2.c
   Hacl_Hash_SHA1.c
   Hacl_Hash_MD5.c
+  Hacl_Hash_SHA3.c
 )
 
 declare -a include_files
@@ -134,9 +137,9 @@ $sed -i -z 's!#include <string.h>\n!#include <string.h>\n#include "python_hacl_n
 
 # Finally, we remove a bunch of ifdefs from target.h that are, again, useful in
 # the general case, but not exercised by the subset of HACL* that we vendor.
-$sed -z -i 's!#ifndef KRML_\(HOST_PRINTF\|HOST_EXIT\|PRE_ALIGN\|POST_ALIGN\|ALIGNED_MALLOC\|ALIGNED_FREE\|HOST_TIME\)\n\(\n\|#  [^\n]*\n\|[^#][^\n]*\n\)*#endif\n\n!!g' include/krml/internal/target.h
-$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#define KRML_\(EABORT\|EXIT\|CHECK_SIZE\)[^\n]*\(\n  [^\n]*\)*!!g' include/krml/internal/target.h
+$sed -z -i 's!#ifndef KRML_\(PRE_ALIGN\|POST_ALIGN\|ALIGNED_MALLOC\|ALIGNED_FREE\|HOST_TIME\)\n\(\n\|#  [^\n]*\n\|[^#][^\n]*\n\)*#endif\n\n!!g' include/krml/internal/target.h
+$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#define KRML_\(EABORT\|EXIT\)[^\n]*\(\n  [^\n]*\)*!!g' include/krml/internal/target.h
 $sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\(  [^\n]*\n\)*#define  KRML_\(EABORT\|EXIT\|CHECK_SIZE\)[^\n]*\(\n  [^\n]*\)*!!g' include/krml/internal/target.h
-$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\(  [^\n]*\n\)*#  define _\?KRML_\(DEPRECATED\|CHECK_SIZE_PRAGMA\|HOST_EPRINTF\|HOST_SNPRINTF\)[^\n]*\n\([^#][^\n]*\n\|#el[^\n]*\n\|#  [^\n]*\n\)*#endif!!g' include/krml/internal/target.h
+$sed -z -i 's!\n\n\([^#][^\n]*\n\)*#if [^\n]*\n\(  [^\n]*\n\)*#  define _\?KRML_\(DEPRECATED\|HOST_SNPRINTF\)[^\n]*\n\([^#][^\n]*\n\|#el[^\n]*\n\|#  [^\n]*\n\)*#endif!!g' include/krml/internal/target.h
 
 echo "Updated; verify all is okay using git diff and git status."
diff --git a/Modules/_sha3/LICENSE b/Modules/_sha3/LICENSE
deleted file mode 100644
index d2d484d8820dcf..00000000000000
--- a/Modules/_sha3/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Markku-Juhani O. Saarinen
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
diff --git a/Modules/_sha3/README.txt b/Modules/_sha3/README.txt
deleted file mode 100644
index b35919b01677d3..00000000000000
--- a/Modules/_sha3/README.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-tiny_sha3
-=========
-
-https://github.com/mjosaarinen/tiny_sha3
-commit dcbb3192047c2a721f5f851db591871d428036a9
-
-- All functions have been converted to static functions.
-- sha3() function is commented out.
diff --git a/Modules/_sha3/sha3.c b/Modules/_sha3/sha3.c
deleted file mode 100644
index e2d3fd7b8ad855..00000000000000
--- a/Modules/_sha3/sha3.c
+++ /dev/null
@@ -1,193 +0,0 @@
-// sha3.c
-// 19-Nov-11  Markku-Juhani O. Saarinen <mjos@iki.fi>
-
-// Revised 07-Aug-15 to match with official release of FIPS PUB 202 "SHA3"
-// Revised 03-Sep-15 for portability + OpenSSL - style API
-
-#include "sha3.h"
-
-// update the state with given number of rounds
-
-static void sha3_keccakf(uint64_t st[25])
-{
-    // constants
-    const uint64_t keccakf_rndc[24] = {
-        0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
-        0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
-        0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
-        0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
-        0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
-        0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
-        0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
-        0x8000000000008080, 0x0000000080000001, 0x8000000080008008
-    };
-    const int keccakf_rotc[24] = {
-        1,  3,  6,  10, 15, 21, 28, 36, 45, 55, 2,  14,
-        27, 41, 56, 8,  25, 43, 62, 18, 39, 61, 20, 44
-    };
-    const int keccakf_piln[24] = {
-        10, 7,  11, 17, 18, 3, 5,  16, 8,  21, 24, 4,
-        15, 23, 19, 13, 12, 2, 20, 14, 22, 9,  6,  1
-    };
-
-    // variables
-    int i, j, r;
-    uint64_t t, bc[5];
-
-#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
-    uint8_t *v;
-
-    // endianess conversion. this is redundant on little-endian targets
-    for (i = 0; i < 25; i++) {
-        v = (uint8_t *) &st[i];
-        st[i] = ((uint64_t) v[0])     | (((uint64_t) v[1]) << 8) |
-            (((uint64_t) v[2]) << 16) | (((uint64_t) v[3]) << 24) |
-            (((uint64_t) v[4]) << 32) | (((uint64_t) v[5]) << 40) |
-            (((uint64_t) v[6]) << 48) | (((uint64_t) v[7]) << 56);
-    }
-#endif
-
-    // actual iteration
-    for (r = 0; r < KECCAKF_ROUNDS; r++) {
-
-        // Theta
-        for (i = 0; i < 5; i++)
-            bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
-
-        for (i = 0; i < 5; i++) {
-            t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
-            for (j = 0; j < 25; j += 5)
-                st[j + i] ^= t;
-        }
-
-        // Rho Pi
-        t = st[1];
-        for (i = 0; i < 24; i++) {
-            j = keccakf_piln[i];
-            bc[0] = st[j];
-            st[j] = ROTL64(t, keccakf_rotc[i]);
-            t = bc[0];
-        }
-
-        //  Chi
-        for (j = 0; j < 25; j += 5) {
-            for (i = 0; i < 5; i++)
-                bc[i] = st[j + i];
-            for (i = 0; i < 5; i++)
-                st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
-        }
-
-        //  Iota
-        st[0] ^= keccakf_rndc[r];
-    }
-
-#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
-    // endianess conversion. this is redundant on little-endian targets
-    for (i = 0; i < 25; i++) {
-        v = (uint8_t *) &st[i];
-        t = st[i];
-        v[0] = t & 0xFF;
-        v[1] = (t >> 8) & 0xFF;
-        v[2] = (t >> 16) & 0xFF;
-        v[3] = (t >> 24) & 0xFF;
-        v[4] = (t >> 32) & 0xFF;
-        v[5] = (t >> 40) & 0xFF;
-        v[6] = (t >> 48) & 0xFF;
-        v[7] = (t >> 56) & 0xFF;
-    }
-#endif
-}
-
-// Initialize the context for SHA3
-
-static int sha3_init(sha3_ctx_t *c, int mdlen)
-{
-    int i;
-
-    for (i = 0; i < 25; i++)
-        c->st.q[i] = 0;
-    c->mdlen = mdlen;
-    c->rsiz = 200 - 2 * mdlen;
-    c->pt = 0;
-
-    return 1;
-}
-
-// update state with more data
-
-static int sha3_update(sha3_ctx_t *c, const void *data, size_t len)
-{
-    size_t i;
-    int j;
-
-    j = c->pt;
-    for (i = 0; i < len; i++) {
-        c->st.b[j++] ^= ((const uint8_t *) data)[i];
-        if (j >= c->rsiz) {
-            sha3_keccakf(c->st.q);
-            j = 0;
-        }
-    }
-    c->pt = j;
-
-    return 1;
-}
-
-// finalize and output a hash
-
-static int sha3_final(void *md, sha3_ctx_t *c)
-{
-    int i;
-
-    c->st.b[c->pt] ^= 0x06;
-    c->st.b[c->rsiz - 1] ^= 0x80;
-    sha3_keccakf(c->st.q);
-
-    for (i = 0; i < c->mdlen; i++) {
-        ((uint8_t *) md)[i] = c->st.b[i];
-    }
-
-    return 1;
-}
-
-#if 0
-// compute a SHA-3 hash (md) of given byte length from "in"
-
-void *sha3(const void *in, size_t inlen, void *md, int mdlen)
-{
-    sha3_ctx_t sha3;
-
-    sha3_init(&sha3, mdlen);
-    sha3_update(&sha3, in, inlen);
-    sha3_final(md, &sha3);
-
-    return md;
-}
-#endif
-
-// SHAKE128 and SHAKE256 extensible-output functionality
-
-static void shake_xof(sha3_ctx_t *c)
-{
-    c->st.b[c->pt] ^= 0x1F;
-    c->st.b[c->rsiz - 1] ^= 0x80;
-    sha3_keccakf(c->st.q);
-    c->pt = 0;
-}
-
-static void shake_out(sha3_ctx_t *c, void *out, size_t len)
-{
-    size_t i;
-    int j;
-
-    j = c->pt;
-    for (i = 0; i < len; i++) {
-        if (j >= c->rsiz) {
-            sha3_keccakf(c->st.q);
-            j = 0;
-        }
-        ((uint8_t *) out)[i] = c->st.b[j++];
-    }
-    c->pt = j;
-}
-
diff --git a/Modules/_sha3/sha3.h b/Modules/_sha3/sha3.h
deleted file mode 100644
index f973d6733ec2cc..00000000000000
--- a/Modules/_sha3/sha3.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// sha3.h
-// 19-Nov-11  Markku-Juhani O. Saarinen <mjos@iki.fi>
-
-#ifndef SHA3_H
-#define SHA3_H
-
-#include <stddef.h>
-#include <stdint.h>
-
-#ifndef KECCAKF_ROUNDS
-#define KECCAKF_ROUNDS 24
-#endif
-
-#ifndef ROTL64
-#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
-#endif
-
-// state context
-typedef struct {
-    union {                                 // state:
-        uint8_t b[200];                     // 8-bit bytes
-        uint64_t q[25];                     // 64-bit words
-    } st;
-    int pt, rsiz, mdlen;                    // these don't overflow
-} sha3_ctx_t;
-
-// Compression function.
-static void sha3_keccakf(uint64_t st[25]);
-
-// OpenSSL - like interfece
-static int sha3_init(sha3_ctx_t *c, int mdlen);    // mdlen = hash output in bytes
-static int sha3_update(sha3_ctx_t *c, const void *data, size_t len);
-static int sha3_final(void *md, sha3_ctx_t *c);    // digest goes to md
-
-// compute a sha3 hash (md) of given byte length from "in"
-#if 0
-static void *sha3(const void *in, size_t inlen, void *md, int mdlen);
-#endif
-
-// SHAKE128 and SHAKE256 extensible-output functions
-#define shake128_init(c) sha3_init(c, 16)
-#define shake256_init(c) sha3_init(c, 32)
-#define shake_update sha3_update
-
-static void shake_xof(sha3_ctx_t *c);
-static void shake_out(sha3_ctx_t *c, void *out, size_t len);
-
-#endif
-
diff --git a/Modules/_sha3/clinic/sha3module.c.h b/Modules/clinic/sha3module.c.h
similarity index 98%
rename from Modules/_sha3/clinic/sha3module.c.h
rename to Modules/clinic/sha3module.c.h
index a0c7c1c043e515..299803a3420bf6 100644
--- a/Modules/_sha3/clinic/sha3module.c.h
+++ b/Modules/clinic/sha3module.c.h
@@ -12,7 +12,7 @@ PyDoc_STRVAR(py_sha3_new__doc__,
 "sha3_224(data=b\'\', /, *, usedforsecurity=True)\n"
 "--\n"
 "\n"
-"Return a new BLAKE2b hash object.");
+"Return a new SHA3 hash object.");
 
 static PyObject *
 py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity);
@@ -193,4 +193,4 @@ _sha3_shake_128_hexdigest(SHA3object *self, PyObject *arg)
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=747c3f34ddd14063 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=907cb475f3dc9ee0 input=a9049054013a1b77]*/
diff --git a/Modules/_sha3/sha3module.c b/Modules/sha3module.c
similarity index 75%
rename from Modules/_sha3/sha3module.c
rename to Modules/sha3module.c
index 93abc3b2710e55..f05187498a19b3 100644
--- a/Modules/_sha3/sha3module.c
+++ b/Modules/sha3module.c
@@ -22,23 +22,9 @@
 #include "Python.h"
 #include "pycore_strhex.h"        // _Py_strhex()
 #include "pycore_typeobject.h"    // _PyType_GetModuleState()
-#include "../hashlib.h"
-
-#include "sha3.c"
+#include "hashlib.h"
 
 #define SHA3_MAX_DIGESTSIZE 64 /* 64 Bytes (512 Bits) for 224 to 512 */
-#define SHA3_LANESIZE 0
-#define SHA3_state sha3_ctx_t
-#define SHA3_init sha3_init
-#define SHA3_process sha3_update
-#define SHA3_done(state, digest) sha3_final(digest, state)
-#define SHA3_squeeze(state, out, len) shake_xof(state), shake_out(state, out, len)
-#define SHA3_copystate(dest, src) memcpy(&(dest), &(src), sizeof(SHA3_state))
-
-// no optimization
-#define KeccakOpt 0
-
-typedef enum { SUCCESS = 1, FAIL = 0, BAD_HASHLEN = 2 } HashReturn;
 
 typedef struct {
     PyTypeObject *sha3_224_type;
@@ -70,10 +56,11 @@ class _sha3.shake_256 "SHA3object *" "&SHAKE256type"
 
 /* The structure for storing SHA3 info */
 
+#include "_hacl/Hacl_Hash_SHA3.h"
+
 typedef struct {
     PyObject_HEAD
-    SHA3_state hash_state;
-    PyThread_type_lock lock;
+    Hacl_Streaming_Keccak_state *hash_state;
 } SHA3object;
 
 #include "clinic/sha3module.c.h"
@@ -86,10 +73,23 @@ newSHA3object(PyTypeObject *type)
     if (newobj == NULL) {
         return NULL;
     }
-    newobj->lock = NULL;
     return newobj;
 }
 
+static void sha3_update(Hacl_Streaming_Keccak_state *state, uint8_t *buf, Py_ssize_t len) {
+  /* Note: we explicitly ignore the error code on the basis that it would take >
+   * 1 billion years to hash more than 2^64 bytes. */
+#if PY_SSIZE_T_MAX > UINT32_MAX
+  while (len > UINT32_MAX) {
+    Hacl_Streaming_Keccak_update(state, buf, UINT32_MAX);
+    len -= UINT32_MAX;
+    buf += UINT32_MAX;
+  }
+#endif
+  /* Cast to uint32_t is safe: len <= UINT32_MAX at this point. */
+  Hacl_Streaming_Keccak_update(state, buf, (uint32_t) len);
+}
+
 /*[clinic input]
 @classmethod
 _sha3.sha3_224.__new__ as py_sha3_new
@@ -98,14 +98,13 @@ _sha3.sha3_224.__new__ as py_sha3_new
     *
     usedforsecurity: bool = True
 
-Return a new BLAKE2b hash object.
+Return a new SHA3 hash object.
 [clinic start generated code]*/
 
 static PyObject *
 py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity)
-/*[clinic end generated code: output=90409addc5d5e8b0 input=bcfcdf2e4368347a]*/
+/*[clinic end generated code: output=90409addc5d5e8b0 input=637e5f8f6a93982a]*/
 {
-    HashReturn res;
     Py_buffer buf = {NULL, NULL};
     SHA3State *state = _PyType_GetModuleState(type);
     SHA3object *self = newSHA3object(type);
@@ -116,49 +115,29 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity)
     assert(state != NULL);
 
     if (type == state->sha3_224_type) {
-        res = sha3_init(&self->hash_state, 28);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_224);
     } else if (type == state->sha3_256_type) {
-        res = sha3_init(&self->hash_state, 32);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_256);
     } else if (type == state->sha3_384_type) {
-        res = sha3_init(&self->hash_state, 48);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_384);
     } else if (type == state->sha3_512_type) {
-        res = sha3_init(&self->hash_state, 64);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_SHA3_512);
     } else if (type == state->shake_128_type) {
-        res = sha3_init(&self->hash_state, 16);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_Shake128);
     } else if (type == state->shake_256_type) {
-        res = sha3_init(&self->hash_state, 32);
+        self->hash_state = Hacl_Streaming_Keccak_malloc(Spec_Hash_Definitions_Shake256);
     } else {
         PyErr_BadInternalCall();
         goto error;
     }
 
-    if (res != SUCCESS) {
-        PyErr_SetString(PyExc_RuntimeError,
-                        "internal error in SHA3 initialize()");
-        goto error;
-    }
-
     if (data) {
         GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
-        if (buf.len >= HASHLIB_GIL_MINSIZE) {
-            /* invariant: New objects can't be accessed by other code yet,
-             * thus it's safe to release the GIL without locking the object.
-             */
-            Py_BEGIN_ALLOW_THREADS
-            res = SHA3_process(&self->hash_state, buf.buf, buf.len);
-            Py_END_ALLOW_THREADS
-        }
-        else {
-            res = SHA3_process(&self->hash_state, buf.buf, buf.len);
-        }
-        if (res != SUCCESS) {
-            PyErr_SetString(PyExc_RuntimeError,
-                            "internal error in SHA3 Update()");
-            goto error;
-        }
-        PyBuffer_Release(&buf);
+        sha3_update(self->hash_state, buf.buf, buf.len);
     }
 
+    PyBuffer_Release(&buf);
+
     return (PyObject *)self;
 
   error:
@@ -177,10 +156,7 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data, int usedforsecurity)
 static void
 SHA3_dealloc(SHA3object *self)
 {
-    if (self->lock) {
-        PyThread_free_lock(self->lock);
-    }
-
+    Hacl_Streaming_Keccak_free(self->hash_state);
     PyTypeObject *tp = Py_TYPE(self);
     PyObject_Free(self);
     Py_DECREF(tp);
@@ -205,9 +181,7 @@ _sha3_sha3_224_copy_impl(SHA3object *self)
     if ((newobj = newSHA3object(Py_TYPE(self))) == NULL) {
         return NULL;
     }
-    ENTER_HASHLIB(self);
-    SHA3_copystate(newobj->hash_state, self->hash_state);
-    LEAVE_HASHLIB(self);
+    newobj->hash_state = Hacl_Streaming_Keccak_copy(self->hash_state);
     return (PyObject *)newobj;
 }
 
@@ -222,20 +196,12 @@ static PyObject *
 _sha3_sha3_224_digest_impl(SHA3object *self)
 /*[clinic end generated code: output=fd531842e20b2d5b input=5b2a659536bbd248]*/
 {
-    unsigned char digest[SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE];
-    SHA3_state temp;
-    HashReturn res;
-
-    ENTER_HASHLIB(self);
-    SHA3_copystate(temp, self->hash_state);
-    LEAVE_HASHLIB(self);
-    res = SHA3_done(&temp, digest);
-    if (res != SUCCESS) {
-        PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()");
-        return NULL;
-    }
+    unsigned char digest[SHA3_MAX_DIGESTSIZE];
+    // This function errors out if the algorithm is Shake. Here, we know this
+    // not to be the case, and therefore do not perform error checking.
+    Hacl_Streaming_Keccak_finish(self->hash_state, digest);
     return PyBytes_FromStringAndSize((const char *)digest,
-                                      self->hash_state.mdlen);
+        Hacl_Streaming_Keccak_hash_len(self->hash_state));
 }
 
 
@@ -249,21 +215,10 @@ static PyObject *
 _sha3_sha3_224_hexdigest_impl(SHA3object *self)
 /*[clinic end generated code: output=75ad03257906918d input=2d91bb6e0d114ee3]*/
 {
-    unsigned char digest[SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE];
-    SHA3_state temp;
-    HashReturn res;
-
-    /* Get the raw (binary) digest value */
-    ENTER_HASHLIB(self);
-    SHA3_copystate(temp, self->hash_state);
-    LEAVE_HASHLIB(self);
-    res = SHA3_done(&temp, digest);
-    if (res != SUCCESS) {
-        PyErr_SetString(PyExc_RuntimeError, "internal error in SHA3 Final()");
-        return NULL;
-    }
+    unsigned char digest[SHA3_MAX_DIGESTSIZE];
+    Hacl_Streaming_Keccak_finish(self->hash_state, digest);
     return _Py_strhex((const char *)digest,
-                      self->hash_state.mdlen);
+        Hacl_Streaming_Keccak_hash_len(self->hash_state));
 }
 
 
@@ -281,36 +236,8 @@ _sha3_sha3_224_update(SHA3object *self, PyObject *data)
 /*[clinic end generated code: output=d3223352286ed357 input=a887f54dcc4ae227]*/
 {
     Py_buffer buf;
-    HashReturn res;
-
     GET_BUFFER_VIEW_OR_ERROUT(data, &buf);
-
-    /* add new data, the function takes the length in bits not bytes */
-    if (self->lock == NULL && buf.len >= HASHLIB_GIL_MINSIZE) {
-        self->lock = PyThread_allocate_lock();
-    }
-    /* Once a lock exists all code paths must be synchronized. We have to
-     * release the GIL even for small buffers as acquiring the lock may take
-     * an unlimited amount of time when another thread updates this object
-     * with lots of data. */
-    if (self->lock) {
-        Py_BEGIN_ALLOW_THREADS
-        PyThread_acquire_lock(self->lock, 1);
-        res = SHA3_process(&self->hash_state, buf.buf, buf.len);
-        PyThread_release_lock(self->lock);
-        Py_END_ALLOW_THREADS
-    }
-    else {
-        res = SHA3_process(&self->hash_state, buf.buf, buf.len);
-    }
-
-    if (res != SUCCESS) {
-        PyBuffer_Release(&buf);
-        PyErr_SetString(PyExc_RuntimeError,
-                        "internal error in SHA3 Update()");
-        return NULL;
-    }
-
+    sha3_update(self->hash_state, buf.buf, buf.len);
     PyBuffer_Release(&buf);
     Py_RETURN_NONE;
 }
@@ -328,7 +255,7 @@ static PyMethodDef SHA3_methods[] = {
 static PyObject *
 SHA3_get_block_size(SHA3object *self, void *closure)
 {
-    int rate = self->hash_state.rsiz;
+    uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state);
     return PyLong_FromLong(rate);
 }
 
@@ -363,14 +290,19 @@ SHA3_get_name(SHA3object *self, void *closure)
 static PyObject *
 SHA3_get_digest_size(SHA3object *self, void *closure)
 {
-    return PyLong_FromLong(self->hash_state.mdlen);
+    // Preserving previous behavior: variable-length algorithms return 0
+    if (Hacl_Streaming_Keccak_is_shake(self->hash_state))
+      return PyLong_FromLong(0);
+    else
+      return PyLong_FromLong(Hacl_Streaming_Keccak_hash_len(self->hash_state));
 }
 
 
 static PyObject *
 SHA3_get_capacity_bits(SHA3object *self, void *closure)
 {
-    int capacity = 1600 - self->hash_state.rsiz * 8;
+    uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state) * 8;
+    int capacity = 1600 - rate;
     return PyLong_FromLong(capacity);
 }
 
@@ -378,7 +310,7 @@ SHA3_get_capacity_bits(SHA3object *self, void *closure)
 static PyObject *
 SHA3_get_rate_bits(SHA3object *self, void *closure)
 {
-    unsigned int rate = self->hash_state.rsiz * 8;
+    uint32_t rate = Hacl_Streaming_Keccak_block_len(self->hash_state) * 8;
     return PyLong_FromLong(rate);
 }
 
@@ -455,28 +387,26 @@ static PyObject *
 _SHAKE_digest(SHA3object *self, unsigned long digestlen, int hex)
 {
     unsigned char *digest = NULL;
-    SHA3_state temp;
     PyObject *result = NULL;
 
     if (digestlen >= (1 << 29)) {
         PyErr_SetString(PyExc_ValueError, "length is too large");
         return NULL;
     }
-    /* ExtractLane needs at least SHA3_MAX_DIGESTSIZE + SHA3_LANESIZE and
-     * SHA3_LANESIZE extra space.
-     */
-    digest = (unsigned char*)PyMem_Malloc(digestlen + SHA3_LANESIZE);
+    digest = (unsigned char*)PyMem_Malloc(digestlen);
     if (digest == NULL) {
         return PyErr_NoMemory();
     }
 
-    /* Get the raw (binary) digest value */
-    ENTER_HASHLIB(self);
-    SHA3_copystate(temp, self->hash_state);
-    LEAVE_HASHLIB(self);
-    SHA3_squeeze(&temp, digest, digestlen);
+    /* Get the raw (binary) digest value. The HACL functions errors out if:
+     * - the algorith is not shake -- not the case here
+     * - the output length is zero -- we follow the existing behavior and return
+     *   an empty digest, without raising an error */
+    if (digestlen > 0) {
+        Hacl_Streaming_Keccak_squeeze(self->hash_state, digest, digestlen);
+    }
     if (hex) {
-         result = _Py_strhex((const char *)digest, digestlen);
+        result = _Py_strhex((const char *)digest, digestlen);
     } else {
         result = PyBytes_FromStringAndSize((const char *)digest,
                                            digestlen);
@@ -628,11 +558,8 @@ _sha3_exec(PyObject *m)
     init_sha3type(shake_256_type, SHAKE256_spec);
 #undef init_sha3type
 
-    if (PyModule_AddIntConstant(m, "keccakopt", KeccakOpt) < 0) {
-        return -1;
-    }
     if (PyModule_AddStringConstant(m, "implementation",
-                                   "tiny_sha3") < 0) {
+                                   "HACL") < 0) {
         return -1;
     }
 
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 8aafcb786a6064..28b1517c6f6b3a 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -375,13 +375,16 @@
     <ClCompile Include="..\Modules\_contextvarsmodule.c" />
     <ClCompile Include="..\Modules\_csv.c" />
     <ClCompile Include="..\Modules\_functoolsmodule.c" />
+    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_MD5.c" />
+    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c" />
+    <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c" />
+    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA3.c" />
     <ClCompile Include="..\Modules\_heapqmodule.c" />
     <ClCompile Include="..\Modules\_json.c" />
     <ClCompile Include="..\Modules\_localemodule.c" />
     <ClCompile Include="..\Modules\_lsprof.c" />
     <ClCompile Include="..\Modules\_pickle.c" />
     <ClCompile Include="..\Modules\_randommodule.c" />
-    <ClCompile Include="..\Modules\_sha3\sha3module.c" />
     <ClCompile Include="..\Modules\_sre\sre.c" />
     <ClInclude Include="..\Modules\_sre\sre.h" />
     <ClInclude Include="..\Modules\_sre\sre_constants.h" />
@@ -404,17 +407,15 @@
     <ClCompile Include="..\Modules\itertoolsmodule.c" />
     <ClCompile Include="..\Modules\main.c" />
     <ClCompile Include="..\Modules\mathmodule.c" />
-    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_MD5.c" />
     <ClCompile Include="..\Modules\md5module.c" />
     <ClCompile Include="..\Modules\mmapmodule.c" />
     <ClCompile Include="..\Modules\_opcode.c" />
     <ClCompile Include="..\Modules\_operator.c" />
     <ClCompile Include="..\Modules\posixmodule.c" />
     <ClCompile Include="..\Modules\rotatingtree.c" />
-    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c" />
     <ClCompile Include="..\Modules\sha1module.c" />
-    <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c" />
     <ClCompile Include="..\Modules\sha2module.c" />
+    <ClCompile Include="..\Modules\sha3module.c" />
     <ClCompile Include="..\Modules\signalmodule.c" />
     <ClCompile Include="..\Modules\_statisticsmodule.c" />
     <ClCompile Include="..\Modules\symtablemodule.c" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 07476f30833372..75e6fbb13f98ba 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -776,6 +776,15 @@
     <ClCompile Include="..\Modules\_functoolsmodule.c">
       <Filter>Modules</Filter>
     </ClCompile>
+    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c">
+      <Filter>Modules</Filter>
+    </ClCompile>
+    <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c">
+      <Filter>Modules</Filter>
+    </ClCompile>
+    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA3.c">
+      <Filter>Modules</Filter>
+    </ClCompile>
     <ClCompile Include="..\Modules\_heapqmodule.c">
       <Filter>Modules</Filter>
     </ClCompile>
@@ -794,9 +803,6 @@
     <ClCompile Include="..\Modules\_randommodule.c">
       <Filter>Modules</Filter>
     </ClCompile>
-    <ClCompile Include="..\Modules\_sha3\sha3module.c">
-      <Filter>Modules</Filter>
-    </ClCompile>
     <ClCompile Include="..\Modules\_sre\sre.c">
       <Filter>Modules</Filter>
     </ClCompile>
@@ -875,16 +881,13 @@
     <ClCompile Include="..\Modules\rotatingtree.c">
       <Filter>Modules</Filter>
     </ClCompile>
-    <ClCompile Include="..\Modules\_hacl\Hacl_Hash_SHA1.c">
-      <Filter>Modules</Filter>
-    </ClCompile>
     <ClCompile Include="..\Modules\sha1module.c">
       <Filter>Modules</Filter>
     </ClCompile>
-    <ClCompile Include="..\Modules\_hacl\Hacl_Streaming_SHA2.c">
+    <ClCompile Include="..\Modules\sha2module.c">
       <Filter>Modules</Filter>
     </ClCompile>
-    <ClCompile Include="..\Modules\sha2module.c">
+    <ClCompile Include="..\Modules\sha3module.c">
       <Filter>Modules</Filter>
     </ClCompile>
     <ClCompile Include="..\Modules\signalmodule.c">
diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py
index 5924ab7860d8d5..9bd54db0f59c51 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -114,6 +114,7 @@ def clean_lines(text):
 Modules/md5module.c	Modules/_hacl/include
 Modules/sha1module.c	Modules/_hacl/include
 Modules/sha2module.c	Modules/_hacl/include
+Modules/sha3module.c	Modules/_hacl/include
 Objects/stringlib/*.h	Objects
 
 # possible system-installed headers, just in case
@@ -271,13 +272,6 @@ def clean_lines(text):
 Modules/expat/xmlparse.c	XML_POOR_ENTROPY	1
 Modules/_dbmmodule.c	HAVE_GDBM_DASH_NDBM_H	1
 
-# from Modules/_sha3/sha3module.c
-Modules/_sha3/kcp/KeccakP-1600-inplace32BI.c	PLATFORM_BYTE_ORDER	4321  # force big-endian
-Modules/_sha3/kcp/*.c	KeccakOpt	64
-Modules/_sha3/kcp/*.c	KeccakP200_excluded	1
-Modules/_sha3/kcp/*.c	KeccakP400_excluded	1
-Modules/_sha3/kcp/*.c	KeccakP800_excluded	1
-
 # others
 Modules/_sre/sre_lib.h	LOCAL(type)	static inline type
 Modules/_sre/sre_lib.h	SRE(F)	sre_ucs2_##F

From c2683fc46d775d6c4afcb23658c0fd1e328e3c53 Mon Sep 17 00:00:00 2001
From: Itamar Ostricher <itamarost@gmail.com>
Date: Mon, 8 May 2023 04:59:34 -0700
Subject: [PATCH 11/35] gh-97696: Improve and fix documentation for asyncio
 eager tasks (#104256)

---
 Doc/library/asyncio-task.rst                  | 19 ++++++++++++++++++-
 ...-05-03-16-51-53.gh-issue-104144.653Q0P.rst |  3 ++-
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index a46ebc1c3d25a9..b2d7362a9de213 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -560,6 +560,13 @@ Eager Task Factory
     using the provided *custom_task_constructor* when creating a new task instead
     of the default :class:`Task`.
 
+    *custom_task_constructor* must be a *callable* with the signature matching
+    the signature of :class:`Task.__init__ <Task>`.
+    The callable must return a :class:`asyncio.Task`-compatible object.
+
+    This function returns a *callable* intended to be used as a task factory of an
+    event loop via :meth:`loop.set_task_factory(factory) <loop.set_task_factory>`).
+
     .. versionadded:: 3.12
 
 
@@ -1014,7 +1021,7 @@ Introspection
 Task Object
 ===========
 
-.. class:: Task(coro, *, loop=None, name=None, context=None)
+.. class:: Task(coro, *, loop=None, name=None, context=None, eager_start=False)
 
    A :class:`Future-like <Future>` object that runs a Python
    :ref:`coroutine <coroutine>`.  Not thread-safe.
@@ -1054,6 +1061,13 @@ Task Object
    If no *context* is provided, the Task copies the current context
    and later runs its coroutine in the copied context.
 
+   An optional keyword-only *eager_start* argument allows eagerly starting
+   the execution of the :class:`asyncio.Task` at task creation time.
+   If set to ``True`` and the event loop is running, the task will start
+   executing the coroutine immediately, until the first time the coroutine
+   blocks. If the coroutine returns or raises without blocking, the task
+   will be finished eagerly and will skip scheduling to the event loop.
+
    .. versionchanged:: 3.7
       Added support for the :mod:`contextvars` module.
 
@@ -1067,6 +1081,9 @@ Task Object
    .. versionchanged:: 3.11
       Added the *context* parameter.
 
+   .. versionchanged:: 3.12
+      Added the *eager_start* parameter.
+
    .. method:: done()
 
       Return ``True`` if the Task is *done*.
diff --git a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst
index 59870de3e02edd..ced3b7cea04954 100644
--- a/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst
+++ b/Misc/NEWS.d/next/Library/2023-05-03-16-51-53.gh-issue-104144.653Q0P.rst
@@ -1 +1,2 @@
-Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`. Skip scheduling done callbacks when all tasks finish without blocking.
+Optimize :class:`asyncio.TaskGroup` when using :func:`asyncio.eager_task_factory`.
+Skip scheduling a done callback if a TaskGroup task completes eagerly.

From 1f5679540ca4aa5c0eae06d3a2d5eda34b47e041 Mon Sep 17 00:00:00 2001
From: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
Date: Mon, 8 May 2023 06:40:51 -0700
Subject: [PATCH 12/35] gh-102500: Remove mention of bytes shorthand (#104281)

The bytes shorthand was removed in PEP 688:
https://peps.python.org/pep-0688/#no-special-meaning-for-bytes

I also remove the reference to `collections.abc.ByteString`, since that
object is deprecated (#91896) and has different semantics (#102092)
---
 Doc/library/typing.rst | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 162041fc7a846e..ebab1389f07e58 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -2130,15 +2130,10 @@ Corresponding to collections in :mod:`collections.abc`
 
 .. class:: ByteString(Sequence[int])
 
-   A generic version of :class:`collections.abc.ByteString`.
-
    This type represents the types :class:`bytes`, :class:`bytearray`,
    and :class:`memoryview` of byte sequences.
 
-   As a shorthand for this type, :class:`bytes` can be used to
-   annotate arguments of any of the types mentioned above.
-
-   .. deprecated:: 3.9
+   .. deprecated-removed:: 3.9 3.14
       Prefer :class:`collections.abc.Buffer`, or a union like ``bytes | bytearray | memoryview``.
 
 .. class:: Collection(Sized, Iterable[T_co], Container[T_co])
@@ -2977,6 +2972,8 @@ convenience. This is subject to change, and not all deprecations are listed.
 |  ``typing`` versions of standard | 3.9           | Undecided         | :pep:`585`     |
 |  collections                     |               |                   |                |
 +----------------------------------+---------------+-------------------+----------------+
+|  ``typing.ByteString``           | 3.9           | 3.14              | :gh:`91896`    |
++----------------------------------+---------------+-------------------+----------------+
 |  ``typing.Text``                 | 3.11          | Undecided         | :gh:`92332`    |
 +----------------------------------+---------------+-------------------+----------------+
 |  ``typing.Hashable`` and         | 3.12          | Undecided         | :gh:`94309`    |

From d513ddee94a05783b98f2b55f8fc0a4efbb9be82 Mon Sep 17 00:00:00 2001
From: Hugo van Kemenade <hugovk@users.noreply.github.com>
Date: Mon, 8 May 2023 17:03:52 +0300
Subject: [PATCH 13/35] Trim trailing whitespace and test on CI (#104275)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
---
 .github/CODEOWNERS                      |  3 +++
 .github/workflows/lint.yml              | 22 ++++++++++++++++++++++
 .pre-commit-config.yaml                 |  7 +++++++
 Modules/_blake2/blake2module.h          |  2 +-
 Modules/_blake2/impl/blake2b-round.h    |  4 ++--
 Modules/_blake2/impl/blake2s-load-xop.h |  2 +-
 Modules/_blake2/impl/blake2s-round.h    |  2 +-
 Modules/_ctypes/_ctypes_test.c          |  2 +-
 Modules/_testcapi/immortal.c            |  2 +-
 Modules/termios.c                       |  4 ++--
 Parser/tokenizer.c                      |  2 +-
 Tools/msi/bundle/bootstrap/pch.h        |  2 +-
 Tools/msi/bundle/bootstrap/resource.h   |  2 +-
 13 files changed, 44 insertions(+), 12 deletions(-)
 create mode 100644 .github/workflows/lint.yml
 create mode 100644 .pre-commit-config.yaml

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 3422ef835279bc..d40519e40d3cc2 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -7,6 +7,9 @@
 # GitHub
 .github/**                    @ezio-melotti @hugovk
 
+# pre-commit
+.pre-commit-config.yaml       @hugovk @AlexWaygood
+
 # Build system
 configure*                    @erlend-aasland @corona10
 
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 00000000000000..4481ea80bfd936
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,22 @@
+name: Lint
+
+on: [push, pull_request, workflow_dispatch]
+
+permissions:
+  contents: read
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+  cancel-in-progress: true
+
+jobs:
+  lint:
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-python@v4
+        with:
+          python-version: "3.x"
+      - uses: pre-commit/action@v3.0.0
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 00000000000000..808622f19a3dbf
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,7 @@
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.4.0
+    hooks:
+      - id: check-yaml
+      - id: trailing-whitespace
+        types_or: [c, python, rst]
diff --git a/Modules/_blake2/blake2module.h b/Modules/_blake2/blake2module.h
index aa8f281178eadc..c8144ec9d48d29 100644
--- a/Modules/_blake2/blake2module.h
+++ b/Modules/_blake2/blake2module.h
@@ -38,6 +38,6 @@
 #endif // HAVE_LIBB2
 
 // for secure_zero_memory(), store32(), store48(), and store64()
-#include "impl/blake2-impl.h" 
+#include "impl/blake2-impl.h"
 
 #endif // Py_BLAKE2MODULE_H
diff --git a/Modules/_blake2/impl/blake2b-round.h b/Modules/_blake2/impl/blake2b-round.h
index cebc22550da4cd..5b452c4d63babe 100644
--- a/Modules/_blake2/impl/blake2b-round.h
+++ b/Modules/_blake2/impl/blake2b-round.h
@@ -62,7 +62,7 @@
   \
   row2l = _mm_roti_epi64(row2l, -24); \
   row2h = _mm_roti_epi64(row2h, -24); \
- 
+
 #define G2(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h,b0,b1) \
   row1l = _mm_add_epi64(_mm_add_epi64(row1l, b0), row2l); \
   row1h = _mm_add_epi64(_mm_add_epi64(row1h, b1), row2h); \
@@ -81,7 +81,7 @@
   \
   row2l = _mm_roti_epi64(row2l, -63); \
   row2h = _mm_roti_epi64(row2h, -63); \
- 
+
 #if defined(HAVE_SSSE3)
 #define DIAGONALIZE(row1l,row2l,row3l,row4l,row1h,row2h,row3h,row4h) \
   t0 = _mm_alignr_epi8(row2h, row2l, 8); \
diff --git a/Modules/_blake2/impl/blake2s-load-xop.h b/Modules/_blake2/impl/blake2s-load-xop.h
index ac591a77d191a7..14d9e7f7640672 100644
--- a/Modules/_blake2/impl/blake2s-load-xop.h
+++ b/Modules/_blake2/impl/blake2s-load-xop.h
@@ -166,7 +166,7 @@ buf = _mm_perm_epi8(t1, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(1),TOB(7)) );
 #define LOAD_MSG_8_3(buf) \
 t0 = _mm_perm_epi8(m0, m2, _mm_set_epi32(TOB(6),TOB(1),TOB(0),TOB(0)) ); \
 buf = _mm_perm_epi8(t0, m3, _mm_set_epi32(TOB(3),TOB(2),TOB(5),TOB(4)) ); \
- 
+
 #define LOAD_MSG_8_4(buf) \
 buf = _mm_perm_epi8(m0, m1, _mm_set_epi32(TOB(5),TOB(4),TOB(7),TOB(2)) );
 
diff --git a/Modules/_blake2/impl/blake2s-round.h b/Modules/_blake2/impl/blake2s-round.h
index 1e2f2b7f59bd6c..3af4be35bee5d4 100644
--- a/Modules/_blake2/impl/blake2s-round.h
+++ b/Modules/_blake2/impl/blake2s-round.h
@@ -86,6 +86,6 @@
   LOAD_MSG_ ##r ##_4(buf4); \
   G2(row1,row2,row3,row4,buf4); \
   UNDIAGONALIZE(row1,row2,row3,row4); \
- 
+
 #endif
 
diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c
index ce652b362d5bb3..ddfb2c8a332a9e 100644
--- a/Modules/_ctypes/_ctypes_test.c
+++ b/Modules/_ctypes/_ctypes_test.c
@@ -1036,7 +1036,7 @@ EXPORT (HRESULT) KeepObject(IUnknown *punk)
 
 #ifdef MS_WIN32
 
-// i38748: c stub for testing stack corruption 
+// i38748: c stub for testing stack corruption
 // When executing a Python callback with a long and a long long
 
 typedef long(__stdcall *_test_i38748_funcType)(long, long long);
diff --git a/Modules/_testcapi/immortal.c b/Modules/_testcapi/immortal.c
index 10e1733d08a9ea..9f81389811c645 100644
--- a/Modules/_testcapi/immortal.c
+++ b/Modules/_testcapi/immortal.c
@@ -1,6 +1,6 @@
 #include "parts.h"
 
-int verify_immortality(PyObject *object) 
+int verify_immortality(PyObject *object)
 {
     assert(_Py_IsImmortal(object));
     Py_ssize_t old_count = Py_REFCNT(object);
diff --git a/Modules/termios.c b/Modules/termios.c
index 169a36fc6477d8..6dc8200572bc0c 100644
--- a/Modules/termios.c
+++ b/Modules/termios.c
@@ -85,7 +85,7 @@ termios_tcgetattr_impl(PyObject *module, int fd)
     int r;
 
     Py_BEGIN_ALLOW_THREADS
-    r = tcgetattr(fd, &mode); 
+    r = tcgetattr(fd, &mode);
     Py_END_ALLOW_THREADS
     if (r == -1) {
         return PyErr_SetFromErrno(state->TermiosError);
@@ -372,7 +372,7 @@ termios_tcgetwinsize_impl(PyObject *module, int fd)
 #if defined(TIOCGWINSZ)
     termiosmodulestate *state = PyModule_GetState(module);
     struct winsize w;
-    int r; 
+    int r;
 
     Py_BEGIN_ALLOW_THREADS
     r = ioctl(fd, TIOCGWINSZ, &w);
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 52d0d9a534cb6a..91ffabac56c7b3 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -48,7 +48,7 @@ static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) {
 }
 static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) {
     assert(tok->tok_mode_stack_index >= 0);
-    assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL); 
+    assert(tok->tok_mode_stack_index + 1 < MAXFSTRINGLEVEL);
     return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]);
 }
 #else
diff --git a/Tools/msi/bundle/bootstrap/pch.h b/Tools/msi/bundle/bootstrap/pch.h
index b0aa5111dabd0d..6d0974b34c61e7 100644
--- a/Tools/msi/bundle/bootstrap/pch.h
+++ b/Tools/msi/bundle/bootstrap/pch.h
@@ -5,7 +5,7 @@
 //   The license and further copyright text can be found in the file
 //   LICENSE.TXT at the root directory of the distribution.
 // </copyright>
-// 
+//
 // <summary>
 //    Precompiled header for standard bootstrapper application.
 // </summary>
diff --git a/Tools/msi/bundle/bootstrap/resource.h b/Tools/msi/bundle/bootstrap/resource.h
index 53c03c319f091f..d951e651f6d20d 100644
--- a/Tools/msi/bundle/bootstrap/resource.h
+++ b/Tools/msi/bundle/bootstrap/resource.h
@@ -14,7 +14,7 @@
 
 
 // Next default values for new objects
-// 
+//
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        102

From 921185ed050efbca2f0adeab79f676b7f8cc3660 Mon Sep 17 00:00:00 2001
From: Alex Waygood <Alex.Waygood@Gmail.com>
Date: Mon, 8 May 2023 15:18:36 +0100
Subject: [PATCH 14/35] gh-103193: Improve `getattr_static` test coverage
 (#104286)

---
 Lib/test/test_inspect.py | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index dd0325a43e0f58..d2b2f3171e785d 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -2187,6 +2187,35 @@ class Thing(metaclass=Meta):
             inspect.getattr_static(Thing, "spam")
         self.assertFalse(Thing.executed)
 
+    def test_custom___getattr__(self):
+        test = self
+        test.called = False
+
+        class Foo:
+            def __getattr__(self, attr):
+                test.called = True
+                return {}
+
+        with self.assertRaises(AttributeError):
+            inspect.getattr_static(Foo(), 'whatever')
+
+        self.assertFalse(test.called)
+
+    def test_custom___getattribute__(self):
+        test = self
+        test.called = False
+
+        class Foo:
+            def __getattribute__(self, attr):
+                test.called = True
+                return {}
+
+        with self.assertRaises(AttributeError):
+            inspect.getattr_static(Foo(), 'really_could_be_anything')
+
+        self.assertFalse(test.called)
+
+
 class TestGetGeneratorState(unittest.TestCase):
 
     def setUp(self):

From 76eef552f3653179782afcc5063f10560a6e1a80 Mon Sep 17 00:00:00 2001
From: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Date: Mon, 8 May 2023 17:32:18 +0100
Subject: [PATCH 15/35] GH-104145: Use fully-qualified cross reference types
 for the bisect module (#104172)

---
 Doc/library/bisect.rst | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/Doc/library/bisect.rst b/Doc/library/bisect.rst
index e3c8c801904b61..8022c596f0af97 100644
--- a/Doc/library/bisect.rst
+++ b/Doc/library/bisect.rst
@@ -24,6 +24,8 @@ method to determine whether a value has been found.  Instead, the
 functions only call the :meth:`__lt__` method and will return an insertion
 point between values in an array.
 
+.. _bisect functions:
+
 The following functions are provided:
 
 
@@ -55,7 +57,7 @@ The following functions are provided:
 .. function:: bisect_right(a, x, lo=0, hi=len(a), *, key=None)
               bisect(a, x, lo=0, hi=len(a), *, key=None)
 
-   Similar to :func:`bisect_left`, but returns an insertion point which comes
+   Similar to :py:func:`~bisect.bisect_left`, but returns an insertion point which comes
    after (to the right of) any existing entries of *x* in *a*.
 
    The returned insertion point *ip* partitions the array *a* into two slices
@@ -70,7 +72,7 @@ The following functions are provided:
 
    Insert *x* in *a* in sorted order.
 
-   This function first runs :func:`bisect_left` to locate an insertion point.
+   This function first runs :py:func:`~bisect.bisect_left` to locate an insertion point.
    Next, it runs the :meth:`insert` method on *a* to insert *x* at the
    appropriate position to maintain sort order.
 
@@ -87,10 +89,10 @@ The following functions are provided:
 .. function:: insort_right(a, x, lo=0, hi=len(a), *, key=None)
               insort(a, x, lo=0, hi=len(a), *, key=None)
 
-   Similar to :func:`insort_left`, but inserting *x* in *a* after any existing
+   Similar to :py:func:`~bisect.insort_left`, but inserting *x* in *a* after any existing
    entries of *x*.
 
-   This function first runs :func:`bisect_right` to locate an insertion point.
+   This function first runs :py:func:`~bisect.bisect_right` to locate an insertion point.
    Next, it runs the :meth:`insert` method on *a* to insert *x* at the
    appropriate position to maintain sort order.
 
@@ -120,7 +122,7 @@ thoughts in mind:
   they are used.  Consequently, if the search functions are used in a loop,
   the key function may be called again and again on the same array elements.
   If the key function isn't fast, consider wrapping it with
-  :func:`functools.cache` to avoid duplicate computations.  Alternatively,
+  :py:func:`functools.cache` to avoid duplicate computations.  Alternatively,
   consider searching an array of precomputed keys to locate the insertion
   point (as shown in the examples section below).
 
@@ -140,7 +142,7 @@ thoughts in mind:
 Searching Sorted Lists
 ----------------------
 
-The above :func:`bisect` functions are useful for finding insertion points but
+The above `bisect functions`_ are useful for finding insertion points but
 can be tricky or awkward to use for common searching tasks. The following five
 functions show how to transform them into the standard lookups for sorted
 lists::
@@ -186,8 +188,8 @@ Examples
 
 .. _bisect-example:
 
-The :func:`bisect` function can be useful for numeric table lookups. This
-example uses :func:`bisect` to look up a letter grade for an exam score (say)
+The :py:func:`~bisect.bisect` function can be useful for numeric table lookups. This
+example uses :py:func:`~bisect.bisect` to look up a letter grade for an exam score (say)
 based on a set of ordered numeric breakpoints: 90 and up is an 'A', 80 to 89 is
 a 'B', and so on::
 
@@ -198,8 +200,8 @@ a 'B', and so on::
    >>> [grade(score) for score in [33, 99, 77, 70, 89, 90, 100]]
    ['F', 'A', 'C', 'C', 'B', 'A', 'A']
 
-The :func:`bisect` and :func:`insort` functions also work with lists of
-tuples.  The *key* argument can serve to extract the field used for ordering
+The :py:func:`~bisect.bisect` and :py:func:`~bisect.insort` functions also work with
+lists of tuples.  The *key* argument can serve to extract the field used for ordering
 records in a table::
 
     >>> from collections import namedtuple

From 874010c6cab2e079069767619af2e0eab05ad0b2 Mon Sep 17 00:00:00 2001
From: Jonathan Protzenko <protz@microsoft.com>
Date: Mon, 8 May 2023 09:52:11 -0700
Subject: [PATCH 16/35] gh-99108: fix typo in Modules/Setup (#104293)

case sensitive filename
---
 Modules/Setup | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Modules/Setup b/Modules/Setup
index e5bc078af62c41..312e99fea530dc 100644
--- a/Modules/Setup
+++ b/Modules/Setup
@@ -166,7 +166,7 @@ PYTHONPATH=$(COREPYTHONPATH)
 #_md5 md5module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_MD5.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 #_sha1 sha1module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA1.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 #_sha2 sha2module.c -I$(srcdir)/Modules/_hacl/include Modules/_hacl/libHacl_Streaming_SHA2.a
-#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_sha3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
+#_sha3 sha3module.c -I$(srcdir)/Modules/_hacl/include _hacl/Hacl_Hash_SHA3.c -D_BSD_SOURCE -D_DEFAULT_SOURCE
 
 # text encodings and unicode
 #_codecs_cn cjkcodecs/_codecs_cn.c

From 405eacc1b87a42e19fd176131e70537f0539e05e Mon Sep 17 00:00:00 2001
From: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Date: Mon, 8 May 2023 09:52:41 -0700
Subject: [PATCH 17/35] gh-104223: Fix issues with inheriting from buffer
 classes (#104227)

Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
---
 Include/cpython/memoryobject.h         |   1 +
 Include/internal/pycore_memoryobject.h |   3 +-
 Lib/test/test_buffer.py                | 170 +++++++++++++++++++++++++
 Objects/bytearrayobject.c              |   1 +
 Objects/memoryobject.c                 |  45 ++++++-
 Objects/typeobject.c                   | 127 ++++++++++++++++--
 6 files changed, 334 insertions(+), 13 deletions(-)

diff --git a/Include/cpython/memoryobject.h b/Include/cpython/memoryobject.h
index deab3cc89f726e..3837fa8c6ab5aa 100644
--- a/Include/cpython/memoryobject.h
+++ b/Include/cpython/memoryobject.h
@@ -24,6 +24,7 @@ typedef struct {
 #define _Py_MEMORYVIEW_FORTRAN     0x004  /* Fortran contiguous layout */
 #define _Py_MEMORYVIEW_SCALAR      0x008  /* scalar: ndim = 0 */
 #define _Py_MEMORYVIEW_PIL         0x010  /* PIL-style layout */
+#define _Py_MEMORYVIEW_RESTRICTED  0x020  /* Disallow new references to the memoryview's buffer */
 
 typedef struct {
     PyObject_VAR_HEAD
diff --git a/Include/internal/pycore_memoryobject.h b/Include/internal/pycore_memoryobject.h
index acc12c9275172c..fe19e3f9611a16 100644
--- a/Include/internal/pycore_memoryobject.h
+++ b/Include/internal/pycore_memoryobject.h
@@ -9,7 +9,8 @@ extern "C" {
 #endif
 
 PyObject *
-PyMemoryView_FromObjectAndFlags(PyObject *v, int flags);
+_PyMemoryView_FromBufferProc(PyObject *v, int flags,
+                             getbufferproc bufferproc);
 
 #ifdef __cplusplus
 }
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index b6e82ad4db266a..2c65ae8114818f 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -4579,6 +4579,176 @@ def test_c_buffer(self):
             buf.__release_buffer__(mv)
         self.assertEqual(buf.references, 0)
 
+    def test_inheritance(self):
+        class A(bytearray):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+
+        a = A(b"hello")
+        mv = memoryview(a)
+        self.assertEqual(mv.tobytes(), b"hello")
+
+    def test_inheritance_releasebuffer(self):
+        rb_call_count = 0
+        class B(bytearray):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+            def __release_buffer__(self, view):
+                nonlocal rb_call_count
+                rb_call_count += 1
+                super().__release_buffer__(view)
+
+        b = B(b"hello")
+        with memoryview(b) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+            self.assertEqual(rb_call_count, 0)
+        self.assertEqual(rb_call_count, 1)
+
+    def test_inherit_but_return_something_else(self):
+        class A(bytearray):
+            def __buffer__(self, flags):
+                return memoryview(b"hello")
+
+        a = A(b"hello")
+        with memoryview(a) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+
+        rb_call_count = 0
+        rb_raised = False
+        class B(bytearray):
+            def __buffer__(self, flags):
+                return memoryview(b"hello")
+            def __release_buffer__(self, view):
+                nonlocal rb_call_count
+                rb_call_count += 1
+                try:
+                    super().__release_buffer__(view)
+                except ValueError:
+                    nonlocal rb_raised
+                    rb_raised = True
+
+        b = B(b"hello")
+        with memoryview(b) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+            self.assertEqual(rb_call_count, 0)
+        self.assertEqual(rb_call_count, 1)
+        self.assertIs(rb_raised, True)
+
+    def test_override_only_release(self):
+        class C(bytearray):
+            def __release_buffer__(self, buffer):
+                super().__release_buffer__(buffer)
+
+        c = C(b"hello")
+        with memoryview(c) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+
+    def test_release_saves_reference(self):
+        smuggled_buffer = None
+
+        class C(bytearray):
+            def __release_buffer__(s, buffer: memoryview):
+                with self.assertRaises(ValueError):
+                    memoryview(buffer)
+                with self.assertRaises(ValueError):
+                    buffer.cast("b")
+                with self.assertRaises(ValueError):
+                    buffer.toreadonly()
+                with self.assertRaises(ValueError):
+                    buffer[:1]
+                with self.assertRaises(ValueError):
+                    buffer.__buffer__(0)
+                nonlocal smuggled_buffer
+                smuggled_buffer = buffer
+                self.assertEqual(buffer.tobytes(), b"hello")
+                super().__release_buffer__(buffer)
+
+        c = C(b"hello")
+        with memoryview(c) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+        c.clear()
+        with self.assertRaises(ValueError):
+            smuggled_buffer.tobytes()
+
+    def test_release_saves_reference_no_subclassing(self):
+        ba = bytearray(b"hello")
+
+        class C:
+            def __buffer__(self, flags):
+                return memoryview(ba)
+
+            def __release_buffer__(self, buffer):
+                self.buffer = buffer
+
+        c = C()
+        with memoryview(c) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+        self.assertEqual(c.buffer.tobytes(), b"hello")
+
+        with self.assertRaises(BufferError):
+            ba.clear()
+        c.buffer.release()
+        ba.clear()
+
+    def test_multiple_inheritance_buffer_last(self):
+        class A:
+            def __buffer__(self, flags):
+                return memoryview(b"hello A")
+
+        class B(A, bytearray):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+
+        b = B(b"hello")
+        with memoryview(b) as mv:
+            self.assertEqual(mv.tobytes(), b"hello A")
+
+        class Releaser:
+            def __release_buffer__(self, buffer):
+                self.buffer = buffer
+
+        class C(Releaser, bytearray):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+
+        c = C(b"hello C")
+        with memoryview(c) as mv:
+            self.assertEqual(mv.tobytes(), b"hello C")
+        c.clear()
+        with self.assertRaises(ValueError):
+            c.buffer.tobytes()
+
+    def test_multiple_inheritance_buffer_last(self):
+        class A:
+            def __buffer__(self, flags):
+                raise RuntimeError("should not be called")
+
+            def __release_buffer__(self, buffer):
+                raise RuntimeError("should not be called")
+
+        class B(bytearray, A):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+
+        b = B(b"hello")
+        with memoryview(b) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+
+        class Releaser:
+            buffer = None
+            def __release_buffer__(self, buffer):
+                self.buffer = buffer
+
+        class C(bytearray, Releaser):
+            def __buffer__(self, flags):
+                return super().__buffer__(flags)
+
+        c = C(b"hello")
+        with memoryview(c) as mv:
+            self.assertEqual(mv.tobytes(), b"hello")
+        c.clear()
+        self.assertIs(c.buffer, None)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c
index 49d4dd524696a5..c36db59baaa10d 100644
--- a/Objects/bytearrayobject.c
+++ b/Objects/bytearrayobject.c
@@ -61,6 +61,7 @@ static void
 bytearray_releasebuffer(PyByteArrayObject *obj, Py_buffer *view)
 {
     obj->ob_exports--;
+    assert(obj->ob_exports >= 0);
 }
 
 static int
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index f008a8cc3e0474..b0168044d9f85a 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -193,6 +193,20 @@ PyTypeObject _PyManagedBuffer_Type = {
         return -1;                                                \
     }
 
+#define CHECK_RESTRICTED(mv) \
+    if (((PyMemoryViewObject *)(mv))->flags & _Py_MEMORYVIEW_RESTRICTED) { \
+        PyErr_SetString(PyExc_ValueError,                                  \
+            "cannot create new view on restricted memoryview");            \
+        return NULL;                                                       \
+    }
+
+#define CHECK_RESTRICTED_INT(mv) \
+    if (((PyMemoryViewObject *)(mv))->flags & _Py_MEMORYVIEW_RESTRICTED) { \
+        PyErr_SetString(PyExc_ValueError,                                  \
+            "cannot create new view on restricted memoryview");            \
+        return -1;                                                       \
+    }
+
 /* See gh-92888. These macros signal that we need to check the memoryview
    again due to possible read after frees. */
 #define CHECK_RELEASED_AGAIN(mv) CHECK_RELEASED(mv)
@@ -781,7 +795,7 @@ PyMemoryView_FromBuffer(const Py_buffer *info)
    using the given flags.
    If the object is a memoryview, the new memoryview must be registered
    with the same managed buffer. Otherwise, a new managed buffer is created. */
-PyObject *
+static PyObject *
 PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
 {
     _PyManagedBufferObject *mbuf;
@@ -789,6 +803,7 @@ PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
     if (PyMemoryView_Check(v)) {
         PyMemoryViewObject *mv = (PyMemoryViewObject *)v;
         CHECK_RELEASED(mv);
+        CHECK_RESTRICTED(mv);
         return mbuf_add_view(mv->mbuf, &mv->view);
     }
     else if (PyObject_CheckBuffer(v)) {
@@ -806,6 +821,30 @@ PyMemoryView_FromObjectAndFlags(PyObject *v, int flags)
         Py_TYPE(v)->tp_name);
     return NULL;
 }
+
+/* Create a memoryview from an object that implements the buffer protocol,
+   using the given flags.
+   If the object is a memoryview, the new memoryview must be registered
+   with the same managed buffer. Otherwise, a new managed buffer is created. */
+PyObject *
+_PyMemoryView_FromBufferProc(PyObject *v, int flags, getbufferproc bufferproc)
+{
+    _PyManagedBufferObject *mbuf = mbuf_alloc();
+    if (mbuf == NULL)
+        return NULL;
+
+    int res = bufferproc(v, &mbuf->master, flags);
+    if (res < 0) {
+        mbuf->master.obj = NULL;
+        Py_DECREF(mbuf);
+        return NULL;
+    }
+
+    PyObject *ret = mbuf_add_view(mbuf, NULL);
+    Py_DECREF(mbuf);
+    return ret;
+}
+
 /* Create a memoryview from an object that implements the buffer protocol.
    If the object is a memoryview, the new memoryview must be registered
    with the same managed buffer. Otherwise, a new managed buffer is created. */
@@ -1397,6 +1436,7 @@ memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format,
     Py_ssize_t ndim = 1;
 
     CHECK_RELEASED(self);
+    CHECK_RESTRICTED(self);
 
     if (!MV_C_CONTIGUOUS(self->flags)) {
         PyErr_SetString(PyExc_TypeError,
@@ -1452,6 +1492,7 @@ memoryview_toreadonly_impl(PyMemoryViewObject *self)
 /*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/
 {
     CHECK_RELEASED(self);
+    CHECK_RESTRICTED(self);
     /* Even if self is already readonly, we still need to create a new
      * object for .release() to work correctly.
      */
@@ -1474,6 +1515,7 @@ memory_getbuf(PyMemoryViewObject *self, Py_buffer *view, int flags)
     int baseflags = self->flags;
 
     CHECK_RELEASED_INT(self);
+    CHECK_RESTRICTED_INT(self);
 
     /* start with complete information */
     *view = *base;
@@ -2535,6 +2577,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key)
         return memory_item(self, index);
     }
     else if (PySlice_Check(key)) {
+        CHECK_RESTRICTED(self);
         PyMemoryViewObject *sliced;
 
         sliced = (PyMemoryViewObject *)mbuf_add_view(self->mbuf, view);
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 456b10ee01d6bc..98fac276a873e1 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -6,7 +6,7 @@
 #include "pycore_symtable.h"      // _Py_Mangle()
 #include "pycore_dict.h"          // _PyDict_KeysSize()
 #include "pycore_initconfig.h"    // _PyStatus_OK()
-#include "pycore_memoryobject.h"  // PyMemoryView_FromObjectAndFlags()
+#include "pycore_memoryobject.h"  // _PyMemoryView_FromBufferProc()
 #include "pycore_moduleobject.h"  // _PyModule_GetDef()
 #include "pycore_object.h"        // _PyType_HasFeature()
 #include "pycore_long.h"          // _PyLong_IsNegative()
@@ -56,6 +56,11 @@ typedef struct PySlot_Offset {
     short slot_offset;
 } PySlot_Offset;
 
+static void
+slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer);
+
+static void
+releasebuffer_call_python(PyObject *self, Py_buffer *buffer);
 
 static PyObject *
 slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
@@ -8078,7 +8083,8 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
         return NULL;
     }
 
-    return PyMemoryView_FromObjectAndFlags(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int));
+    return _PyMemoryView_FromBufferProc(self, Py_SAFE_DOWNCAST(flags, Py_ssize_t, int),
+                                        (getbufferproc)wrapped);
 }
 
 static PyObject *
@@ -8094,6 +8100,10 @@ wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped)
         return NULL;
     }
     PyMemoryViewObject *mview = (PyMemoryViewObject *)arg;
+    if (mview->view.obj == NULL) {
+        // Already released, ignore
+        Py_RETURN_NONE;
+    }
     if (mview->view.obj != self) {
         PyErr_SetString(PyExc_ValueError,
                         "memoryview's buffer is not this object");
@@ -8978,12 +8988,26 @@ bufferwrapper_releasebuf(PyObject *self, Py_buffer *view)
 {
     PyBufferWrapper *bw = (PyBufferWrapper *)self;
 
-    assert(PyMemoryView_Check(bw->mv));
-    Py_TYPE(bw->mv)->tp_as_buffer->bf_releasebuffer(bw->mv, view);
-    if (Py_TYPE(bw->obj)->tp_as_buffer != NULL
-        && Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer != NULL) {
-        Py_TYPE(bw->obj)->tp_as_buffer->bf_releasebuffer(bw->obj, view);
+    if (bw->mv == NULL || bw->obj == NULL) {
+        // Already released
+        return;
+    }
+
+    PyObject *mv = bw->mv;
+    PyObject *obj = bw->obj;
+
+    assert(PyMemoryView_Check(mv));
+    Py_TYPE(mv)->tp_as_buffer->bf_releasebuffer(mv, view);
+    // We only need to call bf_releasebuffer if it's a Python function. If it's a C
+    // bf_releasebuf, it will be called when the memoryview is released.
+    if (((PyMemoryViewObject *)mv)->view.obj != obj
+            && Py_TYPE(obj)->tp_as_buffer != NULL
+            && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer == slot_bf_releasebuffer) {
+        releasebuffer_call_python(obj, view);
     }
+
+    Py_CLEAR(bw->mv);
+    Py_CLEAR(bw->obj);
 }
 
 static PyBufferProcs bufferwrapper_as_buffer = {
@@ -9047,31 +9071,112 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags)
     return -1;
 }
 
+static int
+releasebuffer_maybe_call_super(PyObject *self, Py_buffer *buffer)
+{
+    PyTypeObject *self_type = Py_TYPE(self);
+    PyObject *mro = lookup_tp_mro(self_type);
+    if (mro == NULL) {
+        return -1;
+    }
+
+    assert(PyTuple_Check(mro));
+    Py_ssize_t n = PyTuple_GET_SIZE(mro);
+    Py_ssize_t i;
+
+    /* No need to check the last one: it's gonna be skipped anyway.  */
+    for (i = 0;  i < n -1; i++) {
+        if ((PyObject *)(self_type) == PyTuple_GET_ITEM(mro, i))
+            break;
+    }
+    i++;  /* skip self_type */
+    if (i >= n)
+        return -1;
+
+    releasebufferproc base_releasebuffer = NULL;
+    for (; i < n; i++) {
+        PyObject *obj = PyTuple_GET_ITEM(mro, i);
+        if (!PyType_Check(obj)) {
+            continue;
+        }
+        PyTypeObject *base_type = (PyTypeObject *)obj;
+        if (base_type->tp_as_buffer != NULL
+            && base_type->tp_as_buffer->bf_releasebuffer != NULL
+            && base_type->tp_as_buffer->bf_releasebuffer != slot_bf_releasebuffer) {
+            base_releasebuffer = base_type->tp_as_buffer->bf_releasebuffer;
+            break;
+        }
+    }
+
+    if (base_releasebuffer != NULL) {
+        base_releasebuffer(self, buffer);
+    }
+    return 0;
+}
+
 static void
-slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer)
+releasebuffer_call_python(PyObject *self, Py_buffer *buffer)
 {
     PyObject *mv;
-    if (Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type) {
+    bool is_buffer_wrapper = Py_TYPE(buffer->obj) == &_PyBufferWrapper_Type;
+    if (is_buffer_wrapper) {
         // Make sure we pass the same memoryview to
         // __release_buffer__() that __buffer__() returned.
-        mv = Py_NewRef(((PyBufferWrapper *)buffer->obj)->mv);
+        PyBufferWrapper *bw = (PyBufferWrapper *)buffer->obj;
+        if (bw->mv == NULL) {
+            return;
+        }
+        mv = Py_NewRef(bw->mv);
     }
     else {
+        // This means we are not dealing with a memoryview returned
+        // from a Python __buffer__ function.
         mv = PyMemoryView_FromBuffer(buffer);
         if (mv == NULL) {
             PyErr_WriteUnraisable(self);
             return;
         }
+        // Set the memoryview to restricted mode, which forbids
+        // users from saving any reference to the underlying buffer
+        // (e.g., by doing .cast()). This is necessary to ensure
+        // no Python code retains a reference to the to-be-released
+        // buffer.
+        ((PyMemoryViewObject *)mv)->flags |= _Py_MEMORYVIEW_RESTRICTED;
     }
     PyObject *stack[2] = {self, mv};
     PyObject *ret = vectorcall_method(&_Py_ID(__release_buffer__), stack, 2);
-    Py_DECREF(mv);
     if (ret == NULL) {
         PyErr_WriteUnraisable(self);
     }
     else {
         Py_DECREF(ret);
     }
+    if (!is_buffer_wrapper) {
+        PyObject_CallMethodNoArgs(mv, &_Py_ID(release));
+    }
+    Py_DECREF(mv);
+}
+
+/*
+ * bf_releasebuffer is very delicate, because we need to ensure that
+ * C bf_releasebuffer slots are called correctly (or we'll leak memory),
+ * but we cannot trust any __release_buffer__ implemented in Python to
+ * do so correctly. Therefore, if a base class has a C bf_releasebuffer
+ * slot, we call it directly here. That is safe because this function
+ * only gets called from C callers of the bf_releasebuffer slot. Python
+ * code that calls __release_buffer__ directly instead goes through
+ * wrap_releasebuffer(), which doesn't call the bf_releasebuffer slot
+ * directly but instead simply releases the associated memoryview.
+ */
+static void
+slot_bf_releasebuffer(PyObject *self, Py_buffer *buffer)
+{
+    releasebuffer_call_python(self, buffer);
+    if (releasebuffer_maybe_call_super(self, buffer) < 0) {
+        if (PyErr_Occurred()) {
+            PyErr_WriteUnraisable(self);
+        }
+    }
 }
 
 static PyObject *

From 9af485436b83003b5705a6e54bdeb900c70e0c69 Mon Sep 17 00:00:00 2001
From: Arjun <ccldarjun@icloud.com>
Date: Mon, 8 May 2023 10:55:59 -0700
Subject: [PATCH 18/35] gh-89550: Buffer GzipFile.write to reduce execution
 time by ~15% (#101251)

Use `io.BufferedWriter` to buffer gzip writes.

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
 Lib/gzip.py                                   | 40 ++++++++++++++++---
 ...3-01-22-14-53-12.gh-issue-89550.c1U23f.rst |  2 +
 2 files changed, 37 insertions(+), 5 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst

diff --git a/Lib/gzip.py b/Lib/gzip.py
index 75c6ddc3f2cffb..8796c8d9fd9a2d 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -22,6 +22,7 @@
 _COMPRESS_LEVEL_BEST = 9
 
 READ_BUFFER_SIZE = 128 * 1024
+_WRITE_BUFFER_SIZE = 4 * io.DEFAULT_BUFFER_SIZE
 
 
 def open(filename, mode="rb", compresslevel=_COMPRESS_LEVEL_BEST,
@@ -120,6 +121,21 @@ class BadGzipFile(OSError):
     """Exception raised in some cases for invalid gzip files."""
 
 
+class _WriteBufferStream(io.RawIOBase):
+    """Minimal object to pass WriteBuffer flushes into GzipFile"""
+    def __init__(self, gzip_file):
+        self.gzip_file = gzip_file
+
+    def write(self, data):
+        return self.gzip_file._write_raw(data)
+
+    def seekable(self):
+        return False
+
+    def writable(self):
+        return True
+
+
 class GzipFile(_compression.BaseStream):
     """The GzipFile class simulates most of the methods of a file object with
     the exception of the truncate() method.
@@ -184,6 +200,7 @@ def __init__(self, filename=None, mode=None,
         if mode is None:
             mode = getattr(fileobj, 'mode', 'rb')
 
+
         if mode.startswith('r'):
             self.mode = READ
             raw = _GzipReader(fileobj)
@@ -206,6 +223,9 @@ def __init__(self, filename=None, mode=None,
                                              zlib.DEF_MEM_LEVEL,
                                              0)
             self._write_mtime = mtime
+            self._buffer_size = _WRITE_BUFFER_SIZE
+            self._buffer = io.BufferedWriter(_WriteBufferStream(self),
+                                             buffer_size=self._buffer_size)
         else:
             raise ValueError("Invalid mode: {!r}".format(mode))
 
@@ -231,6 +251,11 @@ def _init_write(self, filename):
         self.bufsize = 0
         self.offset = 0  # Current file offset for seek(), tell(), etc
 
+    def tell(self):
+        self._check_not_closed()
+        self._buffer.flush()
+        return super().tell()
+
     def _write_gzip_header(self, compresslevel):
         self.fileobj.write(b'\037\213')             # magic header
         self.fileobj.write(b'\010')                 # compression method
@@ -272,6 +297,10 @@ def write(self,data):
         if self.fileobj is None:
             raise ValueError("write() on closed GzipFile object")
 
+        return self._buffer.write(data)
+
+    def _write_raw(self, data):
+        # Called by our self._buffer underlying WriteBufferStream.
         if isinstance(data, (bytes, bytearray)):
             length = len(data)
         else:
@@ -322,9 +351,9 @@ def close(self):
         fileobj = self.fileobj
         if fileobj is None:
             return
-        self.fileobj = None
         try:
             if self.mode == WRITE:
+                self._buffer.flush()
                 fileobj.write(self.compress.flush())
                 write32u(fileobj, self.crc)
                 # self.size may exceed 2 GiB, or even 4 GiB
@@ -332,6 +361,7 @@ def close(self):
             elif self.mode == READ:
                 self._buffer.close()
         finally:
+            self.fileobj = None
             myfileobj = self.myfileobj
             if myfileobj:
                 self.myfileobj = None
@@ -341,7 +371,7 @@ def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
         self._check_not_closed()
         if self.mode == WRITE:
             # Ensure the compressor's buffer is flushed
-            self.fileobj.write(self.compress.flush(zlib_mode))
+            self._buffer.flush()
             self.fileobj.flush()
 
     def fileno(self):
@@ -378,10 +408,10 @@ def seek(self, offset, whence=io.SEEK_SET):
             if offset < self.offset:
                 raise OSError('Negative seek in write mode')
             count = offset - self.offset
-            chunk = b'\0' * 1024
-            for i in range(count // 1024):
+            chunk = b'\0' * self._buffer_size
+            for i in range(count // self._buffer_size):
                 self.write(chunk)
-            self.write(b'\0' * (count % 1024))
+            self.write(b'\0' * (count % self._buffer_size))
         elif self.mode == READ:
             self._check_not_closed()
             return self._buffer.seek(offset, whence)
diff --git a/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst b/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst
new file mode 100644
index 00000000000000..556db0eae00c0b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-01-22-14-53-12.gh-issue-89550.c1U23f.rst
@@ -0,0 +1,2 @@
+Decrease execution time of some :mod:`gzip` file writes by 15% by
+adding more appropriate buffering.

From 942482c8e660765f68098eae347d84b93e37661a Mon Sep 17 00:00:00 2001
From: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Date: Mon, 8 May 2023 20:01:25 +0100
Subject: [PATCH 19/35] GH-104284: Fix documentation gettext build (#104296)

---
 Doc/tools/extensions/pyspecific.py | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py
index 4fe54e30b82b25..cd8d9febb0d13b 100644
--- a/Doc/tools/extensions/pyspecific.py
+++ b/Doc/tools/extensions/pyspecific.py
@@ -674,7 +674,14 @@ def process_audit_events(app, doctree, fromdocname):
         node.replace_self(table)
 
 
-def patch_pairindextypes(app) -> None:
+def patch_pairindextypes(app, _env) -> None:
+    """Remove all entries from ``pairindextypes`` before writing POT files.
+
+    We want to run this just before writing output files, as the check to
+    circumvent is in ``I18nBuilder.write_doc()``.
+    As such, we link this to ``env-check-consistency``, even though it has
+    nothing to do with the environment consistency check.
+    """
     if app.builder.name != 'gettext':
         return
 
@@ -688,14 +695,7 @@ def patch_pairindextypes(app) -> None:
         # the Sphinx-translated pairindextypes values. As we intend to move
         # away from this, we need Sphinx to believe that these values don't
         # exist, by deleting them when using the gettext builder.
-
-        pairindextypes.pop('module', None)
-        pairindextypes.pop('keyword', None)
-        pairindextypes.pop('operator', None)
-        pairindextypes.pop('object', None)
-        pairindextypes.pop('exception', None)
-        pairindextypes.pop('statement', None)
-        pairindextypes.pop('builtin', None)
+        pairindextypes.clear()
 
 
 def setup(app):
@@ -719,7 +719,7 @@ def setup(app):
     app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod)
     app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod)
     app.add_directive('miscnews', MiscNews)
-    app.connect('builder-inited', patch_pairindextypes)
+    app.connect('env-check-consistency', patch_pairindextypes)
     app.connect('doctree-resolved', process_audit_events)
     app.connect('env-merge-info', audit_events_merge)
     app.connect('env-purge-doc', audit_events_purge)

From 5c9ee498c6f4b75e0e020f17b6860309c3b7e11e Mon Sep 17 00:00:00 2001
From: Eric Snow <ericsnowcurrently@gmail.com>
Date: Mon, 8 May 2023 13:15:09 -0600
Subject: [PATCH 20/35] gh-99113: A Per-Interpreter GIL! (gh-104210)

This is the culmination of PEP 684 (and of my 8-year long multi-core Python project)!

Each subinterpreter may now be created with its own GIL (via Py_NewInterpreterFromConfig()).  If not so configured then the interpreter will share with the main interpreter--the status quo since subinterpreters were added decades ago.  The main interpreter always has its own GIL and subinterpreters from Py_NewInterpreter() will always share with the main interpreter.
---
 Include/internal/pycore_ceval.h               |  3 +-
 Include/internal/pycore_ceval_state.h         |  3 -
 Include/internal/pycore_interp.h              |  3 +
 Include/internal/pycore_runtime.h             |  2 -
 ...3-05-05-12-14-47.gh-issue-99113.-RAdnv.rst |  6 ++
 Python/ceval_gil.c                            | 55 +++++--------------
 Python/pystate.c                              |  4 +-
 7 files changed, 24 insertions(+), 52 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst

diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 9fd8571cbc87f4..3c8b368bd2af4e 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -21,8 +21,7 @@ struct _ceval_runtime_state;
 
 
 extern void _Py_FinishPendingCalls(PyThreadState *tstate);
-extern void _PyEval_InitRuntimeState(struct _ceval_runtime_state *);
-extern void _PyEval_InitState(struct _ceval_state *, PyThread_type_lock);
+extern void _PyEval_InitState(PyInterpreterState *, PyThread_type_lock);
 extern void _PyEval_FiniState(struct _ceval_state *ceval);
 PyAPI_FUNC(void) _PyEval_SignalReceived(PyInterpreterState *interp);
 PyAPI_FUNC(int) _PyEval_AddPendingCall(
diff --git a/Include/internal/pycore_ceval_state.h b/Include/internal/pycore_ceval_state.h
index 4781dd5735dcf6..b352801673c40a 100644
--- a/Include/internal/pycore_ceval_state.h
+++ b/Include/internal/pycore_ceval_state.h
@@ -49,9 +49,6 @@ struct _ceval_runtime_state {
        the main thread of the main interpreter can handle signals: see
        _Py_ThreadCanHandleSignals(). */
     _Py_atomic_int signals_pending;
-
-    /* This is (only) used indirectly through PyInterpreterState.ceval.gil. */
-    struct _gil_runtime_state gil;
 };
 
 #ifdef PY_HAVE_PERF_TRAMPOLINE
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 7276ce35ba68f0..527b2121148f4c 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -178,6 +178,9 @@ struct _is {
        basis.  Also see _PyRuntimeState regarding the various mutex fields.
        */
 
+    /* The per-interpreter GIL, which might not be used. */
+    struct _gil_runtime_state _gil;
+
     /* the initial PyInterpreterState.threads.head */
     PyThreadState _initial_thread;
 };
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index d1b165d0ab9c38..6e06e874711bc2 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -32,8 +32,6 @@ struct _getargs_runtime_state {
     struct _PyArg_Parser *static_parsers;
 };
 
-/* ceval state */
-
 /* GIL state */
 
 struct _gilstate_runtime_state {
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst
new file mode 100644
index 00000000000000..42e26cb27b6e01
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-05-12-14-47.gh-issue-99113.-RAdnv.rst	
@@ -0,0 +1,6 @@
+The GIL is now (optionally) per-interpreter.  This is the fundamental change
+for PEP 684.  This is all made possible by virtue of the isolated state of
+each interpreter in the process.  The behavior of the main interpreter
+remains unchanged.  Likewise, interpreters created using
+``Py_NewInterpreter()`` are not affected.  To get an interpreter with its
+own GIL, call ``Py_NewInterpreterFromConfig()``.
diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c
index 9958856bae8019..42e1436bc9130d 100644
--- a/Python/ceval_gil.c
+++ b/Python/ceval_gil.c
@@ -464,8 +464,7 @@ take_gil(PyThreadState *tstate)
 
 void _PyEval_SetSwitchInterval(unsigned long microseconds)
 {
-    /* XXX per-interpreter GIL */
-    PyInterpreterState *interp = _PyInterpreterState_Main();
+    PyInterpreterState *interp = _PyInterpreterState_Get();
     struct _gil_runtime_state *gil = interp->ceval.gil;
     assert(gil != NULL);
     gil->interval = microseconds;
@@ -473,8 +472,7 @@ void _PyEval_SetSwitchInterval(unsigned long microseconds)
 
 unsigned long _PyEval_GetSwitchInterval(void)
 {
-    /* XXX per-interpreter GIL */
-    PyInterpreterState *interp = _PyInterpreterState_Main();
+    PyInterpreterState *interp = _PyInterpreterState_Get();
     struct _gil_runtime_state *gil = interp->ceval.gil;
     assert(gil != NULL);
     return gil->interval;
@@ -484,7 +482,9 @@ unsigned long _PyEval_GetSwitchInterval(void)
 int
 _PyEval_ThreadsInitialized(void)
 {
-    /* XXX per-interpreter GIL */
+    /* XXX This is only needed for an assert in PyGILState_Ensure(),
+     * which currently does not work with subinterpreters.
+     * Thus we only use the main interpreter. */
     PyInterpreterState *interp = _PyInterpreterState_Main();
     if (interp == NULL) {
         return 0;
@@ -532,27 +532,16 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil)
     assert(tstate->interp->ceval.gil == NULL);
     int locked;
     if (!own_gil) {
+        /* The interpreter will share the main interpreter's instead. */
         PyInterpreterState *main_interp = _PyInterpreterState_Main();
         assert(tstate->interp != main_interp);
         struct _gil_runtime_state *gil = main_interp->ceval.gil;
         init_shared_gil(tstate->interp, gil);
         locked = current_thread_holds_gil(gil, tstate);
     }
-    /* XXX per-interpreter GIL */
-    else if (!_Py_IsMainInterpreter(tstate->interp)) {
-        /* Currently, the GIL is shared by all interpreters,
-           and only the main interpreter is responsible to create
-           and destroy it. */
-        struct _gil_runtime_state *main_gil = _PyInterpreterState_Main()->ceval.gil;
-        init_shared_gil(tstate->interp, main_gil);
-        // XXX For now we lie.
-        tstate->interp->ceval.own_gil = 1;
-        locked = current_thread_holds_gil(main_gil, tstate);
-    }
     else {
         PyThread_init_thread();
-        // XXX per-interpreter GIL: switch to interp->_gil.
-        init_own_gil(tstate->interp, &tstate->interp->runtime->ceval.gil);
+        init_own_gil(tstate->interp, &tstate->interp->_gil);
         locked = 0;
     }
     if (!locked) {
@@ -565,7 +554,8 @@ _PyEval_InitGIL(PyThreadState *tstate, int own_gil)
 void
 _PyEval_FiniGIL(PyInterpreterState *interp)
 {
-    if (interp->ceval.gil == NULL) {
+    struct _gil_runtime_state *gil = interp->ceval.gil;
+    if (gil == NULL) {
         /* It was already finalized (or hasn't been initialized yet). */
         assert(!interp->ceval.own_gil);
         return;
@@ -573,24 +563,13 @@ _PyEval_FiniGIL(PyInterpreterState *interp)
     else if (!interp->ceval.own_gil) {
 #ifdef Py_DEBUG
         PyInterpreterState *main_interp = _PyInterpreterState_Main();
-        assert(interp != main_interp);
+        assert(main_interp != NULL && interp != main_interp);
         assert(interp->ceval.gil == main_interp->ceval.gil);
 #endif
         interp->ceval.gil = NULL;
         return;
     }
 
-    /* XXX per-interpreter GIL */
-    struct _gil_runtime_state *gil = &interp->runtime->ceval.gil;
-    if (!_Py_IsMainInterpreter(interp)) {
-        /* Currently, the GIL is shared by all interpreters,
-           and only the main interpreter is responsible to create
-           and destroy it. */
-        assert(interp->ceval.gil == gil);
-        interp->ceval.gil = NULL;
-        return;
-    }
-
     if (!gil_created(gil)) {
         /* First Py_InitializeFromConfig() call: the GIL doesn't exist
            yet: do nothing. */
@@ -974,21 +953,13 @@ Py_MakePendingCalls(void)
     return 0;
 }
 
-/* The interpreter's recursion limit */
-
 void
-_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval)
+_PyEval_InitState(PyInterpreterState *interp, PyThread_type_lock pending_lock)
 {
-    /* XXX per-interpreter GIL */
-    _gil_initialize(&ceval->gil);
-}
+    _gil_initialize(&interp->_gil);
 
-void
-_PyEval_InitState(struct _ceval_state *ceval, PyThread_type_lock pending_lock)
-{
-    struct _pending_calls *pending = &ceval->pending;
+    struct _pending_calls *pending = &interp->ceval.pending;
     assert(pending->lock == NULL);
-
     pending->lock = pending_lock;
 }
 
diff --git a/Python/pystate.c b/Python/pystate.c
index f14934361dab78..26debf1f88b94a 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -425,8 +425,6 @@ init_runtime(_PyRuntimeState *runtime,
     runtime->open_code_userdata = open_code_userdata;
     runtime->audit_hook_head = audit_hook_head;
 
-    _PyEval_InitRuntimeState(&runtime->ceval);
-
     PyPreConfig_InitPythonConfig(&runtime->preconfig);
 
     PyThread_type_lock *lockptrs[NUMLOCKS] = {
@@ -682,7 +680,7 @@ init_interpreter(PyInterpreterState *interp,
         memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp));
     }
 
-    _PyEval_InitState(&interp->ceval, pending_lock);
+    _PyEval_InitState(interp, pending_lock);
     _PyGC_InitState(&interp->gc);
     PyConfig_InitPythonConfig(&interp->config);
     _PyType_InitCache(interp);

From 4541d1a0dba3ef0c386991cf54c4c3c411a364c0 Mon Sep 17 00:00:00 2001
From: Eric Snow <ericsnowcurrently@gmail.com>
Date: Mon, 8 May 2023 16:56:01 -0600
Subject: [PATCH 21/35] gh-104310: Add importlib.util.allowing_all_extensions()
 (gh-104311)

(I'll be adding docs for this separately.)
---
 Lib/importlib/util.py                         |  37 ++++++
 Lib/test/support/import_helper.py             |   2 +
 Lib/test/test_importlib/test_util.py          | 121 ++++++++++++++++++
 ...-05-08-15-50-59.gh-issue-104310.fXVSPY.rst |   3 +
 4 files changed, 163 insertions(+)
 create mode 100644 Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst

diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index 5294578cc26cf3..b1d9271f8e47ca 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -112,6 +112,43 @@ def find_spec(name, package=None):
             return spec
 
 
+# Normally we would use contextlib.contextmanager.  However, this module
+# is imported by runpy, which means we want to avoid any unnecessary
+# dependencies.  Thus we use a class.
+
+class allowing_all_extensions:
+    """A context manager that lets users skip the compatibility check.
+
+    Normally, extensions that do not support multiple interpreters
+    may not be imported in a subinterpreter.  That implies modules
+    that do not implement multi-phase init.
+
+    Likewise for modules import in a subinterpeter with its own GIL
+    when the extension does not support a per-interpreter GIL.  This
+    implies the module does not have a Py_mod_multiple_interpreters slot
+    set to Py_MOD_PER_INTERPRETER_GIL_SUPPORTED.
+
+    In both cases, this context manager may be used to temporarily
+    disable the check for compatible extension modules.
+    """
+
+    def __init__(self, disable_check=True):
+        self.disable_check = disable_check
+
+    def __enter__(self):
+        self.old = _imp._override_multi_interp_extensions_check(self.override)
+        return self
+
+    def __exit__(self, *args):
+        old = self.old
+        del self.old
+        _imp._override_multi_interp_extensions_check(old)
+
+    @property
+    def override(self):
+        return -1 if self.disable_check else 1
+
+
 class _LazyModule(types.ModuleType):
 
     """A subclass of the module type which triggers loading upon attribute access."""
diff --git a/Lib/test/support/import_helper.py b/Lib/test/support/import_helper.py
index 772c0987c2ebef..67f18e530edc4b 100644
--- a/Lib/test/support/import_helper.py
+++ b/Lib/test/support/import_helper.py
@@ -115,6 +115,8 @@ def multi_interp_extensions_check(enabled=True):
     It overrides the PyInterpreterConfig.check_multi_interp_extensions
     setting (see support.run_in_subinterp_with_config() and
     _xxsubinterpreters.create()).
+
+    Also see importlib.utils.allowing_all_extensions().
     """
     old = _imp._override_multi_interp_extensions_check(1 if enabled else -1)
     try:
diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py
index 08a615ecf5288b..0be504925ecc6a 100644
--- a/Lib/test/test_importlib/test_util.py
+++ b/Lib/test/test_importlib/test_util.py
@@ -8,14 +8,29 @@
 import importlib.util
 import os
 import pathlib
+import re
 import string
 import sys
 from test import support
+import textwrap
 import types
 import unittest
 import unittest.mock
 import warnings
 
+try:
+    import _testsinglephase
+except ImportError:
+    _testsinglephase = None
+try:
+    import _testmultiphase
+except ImportError:
+    _testmultiphase = None
+try:
+    import _xxsubinterpreters as _interpreters
+except ModuleNotFoundError:
+    _interpreters = None
+
 
 class DecodeSourceBytesTests:
 
@@ -637,5 +652,111 @@ def test_magic_number(self):
         self.assertEqual(EXPECTED_MAGIC_NUMBER, actual, msg)
 
 
+@unittest.skipIf(_interpreters is None, 'subinterpreters required')
+class AllowingAllExtensionsTests(unittest.TestCase):
+
+    ERROR = re.compile("^<class 'ImportError'>: module (.*) does not support loading in subinterpreters")
+
+    def run_with_own_gil(self, script):
+        interpid = _interpreters.create(isolated=True)
+        try:
+            _interpreters.run_string(interpid, script)
+        except _interpreters.RunFailedError as exc:
+            if m := self.ERROR.match(str(exc)):
+                modname, = m.groups()
+                raise ImportError(modname)
+
+    def run_with_shared_gil(self, script):
+        interpid = _interpreters.create(isolated=False)
+        try:
+            _interpreters.run_string(interpid, script)
+        except _interpreters.RunFailedError as exc:
+            if m := self.ERROR.match(str(exc)):
+                modname, = m.groups()
+                raise ImportError(modname)
+
+    @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
+    def test_single_phase_init_module(self):
+        script = textwrap.dedent('''
+            import importlib.util
+            with importlib.util.allowing_all_extensions():
+                import _testsinglephase
+            ''')
+        with self.subTest('check disabled, shared GIL'):
+            self.run_with_shared_gil(script)
+        with self.subTest('check disabled, per-interpreter GIL'):
+            self.run_with_own_gil(script)
+
+        script = textwrap.dedent(f'''
+            import importlib.util
+            with importlib.util.allowing_all_extensions(False):
+                import _testsinglephase
+            ''')
+        with self.subTest('check enabled, shared GIL'):
+            with self.assertRaises(ImportError):
+                self.run_with_shared_gil(script)
+        with self.subTest('check enabled, per-interpreter GIL'):
+            with self.assertRaises(ImportError):
+                self.run_with_own_gil(script)
+
+    @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
+    def test_incomplete_multi_phase_init_module(self):
+        prescript = textwrap.dedent(f'''
+            from importlib.util import spec_from_loader, module_from_spec
+            from importlib.machinery import ExtensionFileLoader
+
+            name = '_test_shared_gil_only'
+            filename = {_testmultiphase.__file__!r}
+            loader = ExtensionFileLoader(name, filename)
+            spec = spec_from_loader(name, loader)
+
+            ''')
+
+        script = prescript + textwrap.dedent('''
+            import importlib.util
+            with importlib.util.allowing_all_extensions():
+                module = module_from_spec(spec)
+                loader.exec_module(module)
+            ''')
+        with self.subTest('check disabled, shared GIL'):
+            self.run_with_shared_gil(script)
+        with self.subTest('check disabled, per-interpreter GIL'):
+            self.run_with_own_gil(script)
+
+        script = prescript + textwrap.dedent('''
+            import importlib.util
+            with importlib.util.allowing_all_extensions(False):
+                module = module_from_spec(spec)
+                loader.exec_module(module)
+            ''')
+        with self.subTest('check enabled, shared GIL'):
+            self.run_with_shared_gil(script)
+        with self.subTest('check enabled, per-interpreter GIL'):
+            with self.assertRaises(ImportError):
+                self.run_with_own_gil(script)
+
+    @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
+    def test_complete_multi_phase_init_module(self):
+        script = textwrap.dedent('''
+            import importlib.util
+            with importlib.util.allowing_all_extensions():
+                import _testmultiphase
+            ''')
+        with self.subTest('check disabled, shared GIL'):
+            self.run_with_shared_gil(script)
+        with self.subTest('check disabled, per-interpreter GIL'):
+            self.run_with_own_gil(script)
+
+        script = textwrap.dedent(f'''
+            import importlib.util
+            with importlib.util.allowing_all_extensions(False):
+                import _testmultiphase
+            ''')
+        with self.subTest('check enabled, shared GIL'):
+            self.run_with_shared_gil(script)
+        with self.subTest('check enabled, per-interpreter GIL'):
+            self.run_with_own_gil(script)
+
+
 if __name__ == '__main__':
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst b/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst
new file mode 100644
index 00000000000000..3743d569995f2e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-08-15-50-59.gh-issue-104310.fXVSPY.rst
@@ -0,0 +1,3 @@
+Users may now use ``importlib.util.allowing_all_extensions()`` (a context
+manager) to temporarily disable the strict compatibility checks for
+importing extension modules in subinterpreters.

From faf196213e60d8a90773e9e5680d3252bd294643 Mon Sep 17 00:00:00 2001
From: "Nathaniel J. Smith" <njs@pobox.com>
Date: Mon, 8 May 2023 16:27:20 -0700
Subject: [PATCH 22/35] GH-104308: socket.getnameinfo should release the GIL
 (#104307)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* socket.getnameinfo should release the GIL

* 📜🤖 Added by blurb_it.

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
---
 .../next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst | 1 +
 Modules/socketmodule.c                                          | 2 ++
 2 files changed, 3 insertions(+)
 create mode 100644 Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst

diff --git a/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst
new file mode 100644
index 00000000000000..03775845450caa
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-08-20-57-17.gh-issue-104307.DSB93G.rst
@@ -0,0 +1 @@
+:func:`socket.getnameinfo` now releases the GIL while contacting the DNS server
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 60219593be61e2..c11fb4400eab2f 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -6883,8 +6883,10 @@ socket_getnameinfo(PyObject *self, PyObject *args)
         }
 #endif
     }
+    Py_BEGIN_ALLOW_THREADS
     error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen,
                     hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
+    Py_END_ALLOW_THREADS
     if (error) {
         socket_state *state = get_module_state(self);
         set_gaierror(state, error);

From bf89d4283a28dd00836f2c312a9255f543f93fc7 Mon Sep 17 00:00:00 2001
From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com>
Date: Mon, 8 May 2023 17:51:58 -0700
Subject: [PATCH 23/35]  gh-97696 Remove unnecessary check for eager_start
 kwarg (#104188)

Instead, add docstring to create_eager_task_factory.
---
 Lib/asyncio/tasks.py | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 7eb647bd129819..8d5bde09ea9b5b 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -942,18 +942,31 @@ def callback():
 
 
 def create_eager_task_factory(custom_task_constructor):
+    """Create a function suitable for use as a task factory on an event-loop.
 
-    if "eager_start" not in inspect.signature(custom_task_constructor).parameters:
-        raise TypeError(
-            "Provided constructor does not support eager task execution")
+	    Example usage:
+
+	        loop.set_task_factory(
+	            asyncio.create_eager_task_factory(my_task_constructor))
+
+	    Now, tasks created will be started immediately (rather than being first
+	    scheduled to an event loop). The constructor argument can be any callable
+	    that returns a Task-compatible object and has a signature compatible
+	    with `Task.__init__`; it must have the `eager_start` keyword argument.
+
+	    Most applications will use `Task` for `custom_task_constructor` and in
+        this case there's no need to call `create_eager_task_factory()`
+        directly. Instead the  global `eager_task_factory` instance can be
+        used. E.g. `loop.set_task_factory(asyncio.eager_task_factory)`.
+	    """
 
     def factory(loop, coro, *, name=None, context=None):
         return custom_task_constructor(
             coro, loop=loop, name=name, context=context, eager_start=True)
 
-
     return factory
 
+
 eager_task_factory = create_eager_task_factory(Task)
 
 

From 9a9b176eb7e052af84c01c0cfb3231e51f980f2d Mon Sep 17 00:00:00 2001
From: samschott <sam.schott@outlook.com>
Date: Tue, 9 May 2023 10:24:29 +0200
Subject: [PATCH 24/35] gh-104180: Read SOCKS proxies from macOS System
 Configuration (#104181)

read SOCKS proxies from macOS System Configuration in ``urllib.request``.

---------

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Oleg Iarygin <oleg@arhadthedev.net>
---
 .../macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst     | 2 ++
 Modules/_scproxy.c                                           | 5 +++++
 2 files changed, 7 insertions(+)
 create mode 100644 Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst

diff --git a/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst b/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst
new file mode 100644
index 00000000000000..b6b18dcfd81394
--- /dev/null
+++ b/Misc/NEWS.d/next/macOS/2023-05-04-21-47-59.gh-issue-104180.lEJCwd.rst
@@ -0,0 +1,2 @@
+Support reading SOCKS proxy configuration from macOS System Configuration.
+Patch by Sam Schott.
diff --git a/Modules/_scproxy.c b/Modules/_scproxy.c
index e66918016b8da6..0df0324df55f7d 100644
--- a/Modules/_scproxy.c
+++ b/Modules/_scproxy.c
@@ -206,6 +206,11 @@ get_proxies(PyObject* Py_UNUSED(mod), PyObject *Py_UNUSED(ignored))
         kSCPropNetProxiesGopherProxy,
         kSCPropNetProxiesGopherPort);
     if (r == -1) goto error;
+    r = set_proxy(result, "socks", proxyDict,
+        kSCPropNetProxiesSOCKSEnable,
+        kSCPropNetProxiesSOCKSProxy,
+        kSCPropNetProxiesSOCKSPort);
+    if (r == -1) goto error;
 
     CFRelease(proxyDict);
     return result;

From 03029ace924f7dac7ef49eee3417e0af6623060d Mon Sep 17 00:00:00 2001
From: Zhang Na <44800775+loongson-zn@users.noreply.github.com>
Date: Tue, 9 May 2023 17:19:40 +0800
Subject: [PATCH 25/35] gh-90656: Add platform triplets for 64-bit LoongArch
 (LA64) (#30939)

Signed-off-by: Zhang Na <zhangna@loongson.cn>
Co-authored-by: WANG Xuerui <git@xen0n.name>
---
 Doc/whatsnew/3.12.rst                              |  8 ++++++++
 .../2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst  |  7 +++++++
 configure                                          | 14 ++++++++++++++
 configure.ac                                       | 14 ++++++++++++++
 4 files changed, 43 insertions(+)
 create mode 100644 Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst

diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 65b3e9ffb8072d..fe6ad575f71720 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -1169,6 +1169,14 @@ Build Changes
   optimization levels (0, 1, 2) at once.
   (Contributed by Victor Stinner in :gh:`99289`.)
 
+* Add platform triplets for 64-bit LoongArch:
+
+  * loongarch64-linux-gnusf
+  * loongarch64-linux-gnuf32
+  * loongarch64-linux-gnu
+
+  (Contributed by Zhang Na in :gh:`90656`.)
+
 
 C API Changes
 =============
diff --git a/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst b/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst
new file mode 100644
index 00000000000000..dfe71a5552070d
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2022-06-20-15-15-11.gh-issue-90656.kFBbKe.rst
@@ -0,0 +1,7 @@
+Add platform triplets for 64-bit LoongArch:
+
+* loongarch64-linux-gnusf
+* loongarch64-linux-gnuf32
+* loongarch64-linux-gnu
+
+Patch by Zhang Na.
diff --git a/configure b/configure
index b8fa9d66e735dd..c9ea72cf6efacf 100755
--- a/configure
+++ b/configure
@@ -6143,6 +6143,20 @@ cat > conftest.c <<EOF
         hppa-linux-gnu
 # elif defined(__ia64__)
         ia64-linux-gnu
+# elif defined(__loongarch__)
+#  if defined(__loongarch_lp64)
+#   if defined(__loongarch_soft_float)
+        loongarch64-linux-gnusf
+#   elif defined(__loongarch_single_float)
+        loongarch64-linux-gnuf32
+#   elif defined(__loongarch_double_float)
+        loongarch64-linux-gnu
+#   else
+#    error unknown platform triplet
+#   endif
+#  else
+#   error unknown platform triplet
+#  endif
 # elif defined(__m68k__) && !defined(__mcoldfire__)
         m68k-linux-gnu
 # elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL)
diff --git a/configure.ac b/configure.ac
index 0940b93c25f7bf..10672bd3761da8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -959,6 +959,20 @@ cat > conftest.c <<EOF
         hppa-linux-gnu
 # elif defined(__ia64__)
         ia64-linux-gnu
+# elif defined(__loongarch__)
+#  if defined(__loongarch_lp64)
+#   if defined(__loongarch_soft_float)
+        loongarch64-linux-gnusf
+#   elif defined(__loongarch_single_float)
+        loongarch64-linux-gnuf32
+#   elif defined(__loongarch_double_float)
+        loongarch64-linux-gnu
+#   else
+#    error unknown platform triplet
+#   endif
+#  else
+#   error unknown platform triplet
+#  endif
 # elif defined(__m68k__) && !defined(__mcoldfire__)
         m68k-linux-gnu
 # elif defined(__mips_hard_float) && defined(__mips_isa_rev) && (__mips_isa_rev >=6) && defined(_MIPSEL)

From 41aff464cef83d2655029ddd180a51110e8d7f8e Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Tue, 9 May 2023 12:29:00 +0200
Subject: [PATCH 26/35] require-pr-label.yml: Add missing "permissions:"
 (#104309)

---
 .github/workflows/require-pr-label.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
index 916bbeb4352734..88aaea039f04f4 100644
--- a/.github/workflows/require-pr-label.yml
+++ b/.github/workflows/require-pr-label.yml
@@ -4,6 +4,10 @@ on:
   pull_request:
     types: [opened, reopened, labeled, unlabeled, synchronize]
 
+permissions:
+  issues: read
+  pull-requests: read
+
 jobs:
   label:
     name: DO-NOT-MERGE / unresolved review

From 9196da417d20e1484e23b3c80483b0222abaadf2 Mon Sep 17 00:00:00 2001
From: Alex Waygood <Alex.Waygood@Gmail.com>
Date: Tue, 9 May 2023 13:33:36 +0100
Subject: [PATCH 27/35] gh-103193: Fix refleaks in `test_inspect` and
 `test_typing` (#104320)

---
 Lib/test/libregrtest/utils.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py
index fb13fa0e243ba7..fd46819fd903fe 100644
--- a/Lib/test/libregrtest/utils.py
+++ b/Lib/test/libregrtest/utils.py
@@ -210,6 +210,13 @@ def clear_caches():
     else:
         fractions._hash_algorithm.cache_clear()
 
+    try:
+        inspect = sys.modules['inspect']
+    except KeyError:
+        pass
+    else:
+        inspect._shadowed_dict_from_mro_tuple.cache_clear()
+
 
 def get_build_info():
     # Get most important configure and build options as a list of strings.

From 85f981880ae9591ba577e44d2945a771078a7c35 Mon Sep 17 00:00:00 2001
From: Itamar Ostricher <itamarost@gmail.com>
Date: Tue, 9 May 2023 05:39:59 -0700
Subject: [PATCH 28/35] gh-97696: Move around and update the whatsnew entry for
 asyncio eager task factory (#104298)

---
 Doc/whatsnew/3.12.rst | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index fe6ad575f71720..12d357f117b1b6 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -282,6 +282,11 @@ asyncio
   writing to sockets and uses :meth:`~socket.socket.sendmsg` if the platform
   supports it. (Contributed by Kumar Aditya in :gh:`91166`.)
 
+* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory`
+  functions to allow opting an event loop in to eager task execution,
+  making some use-cases 2x to 5x faster.
+  (Contributed by Jacob Bower & Itamar O in :gh:`102853`, :gh:`104140`, and :gh:`104138`)
+
 * On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default
   if :func:`os.pidfd_open` is available and functional instead of
   :class:`~asyncio.ThreadedChildWatcher`.
@@ -644,11 +649,6 @@ Optimizations
 * Speed up :class:`asyncio.Task` creation by deferring expensive string formatting.
   (Contributed by Itamar O in :gh:`103793`.)
 
-* Added :func:`asyncio.eager_task_factory` and :func:`asyncio.create_eager_task_factory`
-  functions to allow opting an event loop in to eager task execution,
-  speeding up some use-cases by up to 50%.
-  (Contributed by Jacob Bower & Itamar O in :gh:`102853`)
-
 
 CPython bytecode changes
 ========================

From c21f82876089f3e9a7b1e706c029664b799fa659 Mon Sep 17 00:00:00 2001
From: chgnrdv <52372310+chgnrdv@users.noreply.github.com>
Date: Tue, 9 May 2023 15:41:09 +0300
Subject: [PATCH 29/35] gh-104276: Make `_struct.unpack_iterator` type use type
 flag instead of custom constructor (#104277)

---
 Modules/_struct.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/Modules/_struct.c b/Modules/_struct.c
index 26434f714de5cc..4f9478bd98095d 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1832,11 +1832,6 @@ unpackiter_iternext(unpackiterobject *self)
     return result;
 }
 
-PyObject *unpackiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
-    PyErr_Format(PyExc_TypeError, "Cannot create '%.200s objects", _PyType_Name(type));
-    return NULL;
-}
-
 static PyType_Slot unpackiter_type_slots[] = {
     {Py_tp_dealloc, unpackiter_dealloc},
     {Py_tp_getattro, PyObject_GenericGetAttr},
@@ -1844,7 +1839,6 @@ static PyType_Slot unpackiter_type_slots[] = {
     {Py_tp_iter, PyObject_SelfIter},
     {Py_tp_iternext, unpackiter_iternext},
     {Py_tp_methods, unpackiter_methods},
-    {Py_tp_new, unpackiter_new},
     {0, 0},
 };
 
@@ -1853,7 +1847,7 @@ static PyType_Spec unpackiter_type_spec = {
     sizeof(unpackiterobject),
     0,
     (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
-     Py_TPFLAGS_IMMUTABLETYPE),
+     Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
     unpackiter_type_slots
 };
 

From ca95edf177e3c10e10d7011ed52619b1312cf15e Mon Sep 17 00:00:00 2001
From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Date: Tue, 9 May 2023 14:33:40 +0100
Subject: [PATCH 30/35] gh-104240: return code unit metadata from codegen
 (#104300)

---
 Lib/test/support/bytecode_helper.py |  2 +-
 Lib/test/test_compiler_assemble.py  |  2 +-
 Modules/_testinternalcapi.c         |  2 +-
 Python/compile.c                    | 50 +++++++++++++++++++++++++++--
 4 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/Lib/test/support/bytecode_helper.py b/Lib/test/support/bytecode_helper.py
index 357ec44dbc218d..7b577f54b8adc4 100644
--- a/Lib/test/support/bytecode_helper.py
+++ b/Lib/test/support/bytecode_helper.py
@@ -124,7 +124,7 @@ def complete_insts_info(self, insts):
 class CodegenTestCase(CompilationStepTestCase):
 
     def generate_code(self, ast):
-        insts = compiler_codegen(ast, "my_file.py", 0)
+        insts, _ = compiler_codegen(ast, "my_file.py", 0)
         return insts
 
 
diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py
index 96c1691e24a9c8..0bd7a09b001c1d 100644
--- a/Lib/test/test_compiler_assemble.py
+++ b/Lib/test/test_compiler_assemble.py
@@ -52,7 +52,7 @@ def test_simple_expr(self):
             'filename' : 'avg.py',
             'name'     : 'avg',
             'qualname' : 'stats.avg',
-            'consts'   : [2],
+            'consts'   : {2 : 0},
             'argcount' : 2,
             'varnames' : {'x' : 0, 'y' : 1},
         }
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 40ad6f88868daf..8009dca3d0b746 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -670,7 +670,7 @@ _testinternalcapi_assemble_code_object_impl(PyObject *module,
     umd.u_cellvars = PyDict_GetItemString(metadata, "cellvars");
     umd.u_freevars = PyDict_GetItemString(metadata, "freevars");
 
-    assert(PyList_Check(umd.u_consts));
+    assert(PyDict_Check(umd.u_consts));
     assert(PyDict_Check(umd.u_names));
     assert(PyDict_Check(umd.u_varnames));
     assert(PyDict_Check(umd.u_cellvars));
diff --git a/Python/compile.c b/Python/compile.c
index f875e4e17e0a9f..12ae831361963d 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -7261,6 +7261,7 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
                    int optimize, int compile_mode)
 {
     PyObject *res = NULL;
+    PyObject *metadata = NULL;
 
     if (!PyAST_Check(ast)) {
         PyErr_SetString(PyExc_TypeError, "expected an AST");
@@ -7287,14 +7288,53 @@ _PyCompile_CodeGen(PyObject *ast, PyObject *filename, PyCompilerFlags *pflags,
     if (compiler_codegen(c, mod) < 0) {
         goto finally;
     }
+
+    _PyCompile_CodeUnitMetadata *umd = &c->u->u_metadata;
+    metadata = PyDict_New();
+    if (metadata == NULL) {
+        goto finally;
+    }
+#define SET_MATADATA_ITEM(key, value) \
+    if (value != NULL) { \
+        if (PyDict_SetItemString(metadata, key, value) < 0) goto finally; \
+    }
+
+    SET_MATADATA_ITEM("name", umd->u_name);
+    SET_MATADATA_ITEM("qualname", umd->u_qualname);
+    SET_MATADATA_ITEM("consts", umd->u_consts);
+    SET_MATADATA_ITEM("names", umd->u_names);
+    SET_MATADATA_ITEM("varnames", umd->u_varnames);
+    SET_MATADATA_ITEM("cellvars", umd->u_cellvars);
+    SET_MATADATA_ITEM("freevars", umd->u_freevars);
+#undef SET_MATADATA_ITEM
+
+#define SET_MATADATA_INT(key, value) do { \
+        PyObject *v = PyLong_FromLong((long)value); \
+        if (v == NULL) goto finally; \
+        int res = PyDict_SetItemString(metadata, key, v); \
+        Py_XDECREF(v); \
+        if (res < 0) goto finally; \
+    } while (0);
+
+    SET_MATADATA_INT("argcount", umd->u_argcount);
+    SET_MATADATA_INT("posonlyargcount", umd->u_posonlyargcount);
+    SET_MATADATA_INT("kwonlyargcount", umd->u_kwonlyargcount);
+#undef SET_MATADATA_INT
+
     int addNone = mod->kind != Expression_kind;
     if (add_return_at_end(c, addNone) < 0) {
-        return NULL;
+        goto finally;
     }
 
-    res = instr_sequence_to_instructions(INSTR_SEQUENCE(c));
+    PyObject *insts = instr_sequence_to_instructions(INSTR_SEQUENCE(c));
+    if (insts == NULL) {
+        goto finally;
+    }
+    res = PyTuple_Pack(2, insts, metadata);
+    Py_DECREF(insts);
 
 finally:
+    Py_XDECREF(metadata);
     compiler_exit_scope(c);
     compiler_free(c);
     _PyArena_Free(arena);
@@ -7375,10 +7415,14 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
         goto error;
     }
 
-    PyObject *consts = umd->u_consts;
+    PyObject *consts = consts_dict_keys_inorder(umd->u_consts);
+    if (consts == NULL) {
+        goto error;
+    }
     co = _PyAssemble_MakeCodeObject(umd, const_cache,
                                     consts, maxdepth, &optimized_instrs,
                                     nlocalsplus, code_flags, filename);
+    Py_DECREF(consts);
 
 error:
     Py_DECREF(const_cache);

From 82f789be3b15df5f6660f5fd0c563ad690ee00fb Mon Sep 17 00:00:00 2001
From: "Gregory P. Smith" <greg@krypto.org>
Date: Tue, 9 May 2023 07:04:50 -0700
Subject: [PATCH 31/35] gh-104139: Add itms-services to uses_netloc
 urllib.parse. (#104312)

Teach unsplit to retain the `"//"` when assembling `itms-services://?action=generate-bugs` style
[Apple Platform Deployment](https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web) URLs.
---
 Lib/test/test_urlparse.py                     | 33 +++++++++++--------
 Lib/urllib/parse.py                           |  2 +-
 ...-05-08-23-01-59.gh-issue-104139.83Tnt-.rst |  3 ++
 3 files changed, 23 insertions(+), 15 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst

diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
index 80fb9e5cd2a445..dcdbb1cc64fd28 100644
--- a/Lib/test/test_urlparse.py
+++ b/Lib/test/test_urlparse.py
@@ -72,20 +72,20 @@ class UrlParseTestCase(unittest.TestCase):
 
     def checkRoundtrips(self, url, parsed, split):
         result = urllib.parse.urlparse(url)
-        self.assertEqual(result, parsed)
+        self.assertSequenceEqual(result, parsed)
         t = (result.scheme, result.netloc, result.path,
              result.params, result.query, result.fragment)
-        self.assertEqual(t, parsed)
+        self.assertSequenceEqual(t, parsed)
         # put it back together and it should be the same
         result2 = urllib.parse.urlunparse(result)
-        self.assertEqual(result2, url)
-        self.assertEqual(result2, result.geturl())
+        self.assertSequenceEqual(result2, url)
+        self.assertSequenceEqual(result2, result.geturl())
 
         # the result of geturl() is a fixpoint; we can always parse it
         # again to get the same result:
         result3 = urllib.parse.urlparse(result.geturl())
         self.assertEqual(result3.geturl(), result.geturl())
-        self.assertEqual(result3,          result)
+        self.assertSequenceEqual(result3, result)
         self.assertEqual(result3.scheme,   result.scheme)
         self.assertEqual(result3.netloc,   result.netloc)
         self.assertEqual(result3.path,     result.path)
@@ -99,18 +99,18 @@ def checkRoundtrips(self, url, parsed, split):
 
         # check the roundtrip using urlsplit() as well
         result = urllib.parse.urlsplit(url)
-        self.assertEqual(result, split)
+        self.assertSequenceEqual(result, split)
         t = (result.scheme, result.netloc, result.path,
              result.query, result.fragment)
-        self.assertEqual(t, split)
+        self.assertSequenceEqual(t, split)
         result2 = urllib.parse.urlunsplit(result)
-        self.assertEqual(result2, url)
-        self.assertEqual(result2, result.geturl())
+        self.assertSequenceEqual(result2, url)
+        self.assertSequenceEqual(result2, result.geturl())
 
         # check the fixpoint property of re-parsing the result of geturl()
         result3 = urllib.parse.urlsplit(result.geturl())
         self.assertEqual(result3.geturl(), result.geturl())
-        self.assertEqual(result3,          result)
+        self.assertSequenceEqual(result3, result)
         self.assertEqual(result3.scheme,   result.scheme)
         self.assertEqual(result3.netloc,   result.netloc)
         self.assertEqual(result3.path,     result.path)
@@ -162,10 +162,15 @@ def test_roundtrips(self):
              ('svn+ssh', 'svn.zope.org', '/repos/main/ZConfig/trunk/',
               '', '')),
             ('git+ssh://git@github.com/user/project.git',
-            ('git+ssh', 'git@github.com','/user/project.git',
-             '','',''),
-            ('git+ssh', 'git@github.com','/user/project.git',
-             '', '')),
+             ('git+ssh', 'git@github.com','/user/project.git',
+              '','',''),
+             ('git+ssh', 'git@github.com','/user/project.git',
+              '', '')),
+            ('itms-services://?action=download-manifest&url=https://example.com/app',
+             ('itms-services', '', '', '',
+              'action=download-manifest&url=https://example.com/app', ''),
+             ('itms-services', '', '',
+              'action=download-manifest&url=https://example.com/app', '')),
             ]
         def _encode(t):
             return (t[0].encode('ascii'),
diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py
index 5f95c5ff7f9c1c..777b7c53efe565 100644
--- a/Lib/urllib/parse.py
+++ b/Lib/urllib/parse.py
@@ -54,7 +54,7 @@
                'imap', 'wais', 'file', 'mms', 'https', 'shttp',
                'snews', 'prospero', 'rtsp', 'rtspu', 'rsync',
                'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh',
-               'ws', 'wss']
+               'ws', 'wss', 'itms-services']
 
 uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap',
                'https', 'shttp', 'rtsp', 'rtspu', 'sip', 'sips',
diff --git a/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst b/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst
new file mode 100644
index 00000000000000..145e75f6dea6f4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-05-08-23-01-59.gh-issue-104139.83Tnt-.rst
@@ -0,0 +1,3 @@
+Teach :func:`urllib.parse.unsplit` to retain the ``"//"`` when assembling
+``itms-services://?action=generate-bugs`` style `Apple Platform Deployment
+<https://support.apple.com/en-gb/guide/deployment/depce7cefc4d/web>`_ URLs.

From afe7703744f813adb15719642444b5fd35888d86 Mon Sep 17 00:00:00 2001
From: Carl Meyer <carl@oddbird.net>
Date: Tue, 9 May 2023 08:53:19 -0600
Subject: [PATCH 32/35] gh-104184: fix building --with-pydebug --enable-pystats
 (#104217)

---
 Python/specialize.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Python/specialize.c b/Python/specialize.c
index b1cc66124cfa4a..2ccca3a2802c17 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -1455,7 +1455,7 @@ _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *ins
         goto fail;
     }
     if (PyObject_CheckBuffer(container)) {
-        if (PyLong_CheckExact(sub) && (((size_t)Py_SIZE(sub)) > 1)) {
+        if (PyLong_CheckExact(sub) && (!_PyLong_IsNonNegativeCompact((PyLongObject *)sub))) {
             SPECIALIZATION_FAIL(STORE_SUBSCR, SPEC_FAIL_OUT_OF_RANGE);
         }
         else if (strcmp(container_type->tp_name, "array.array") == 0) {

From 0aeda297931820436a50b78f4f7f0597274b5df4 Mon Sep 17 00:00:00 2001
From: Sam Carroll <70000253+samcarroll42@users.noreply.github.com>
Date: Tue, 9 May 2023 12:01:58 -0400
Subject: [PATCH 33/35] gh-99889: Fix directory traversal security flaw in
 uu.decode() (#104096)

* Fix directory traversal security flaw in uu.decode()
* also check absolute paths and os.altsep
* Add a regression test.

---------

Co-authored-by: Gregory P. Smith <greg@krypto.org> [Google]
---
 Lib/test/test_uu.py                           | 28 +++++++++++++++++++
 Lib/uu.py                                     |  9 +++++-
 ...3-05-02-17-56-32.gh-issue-99889.l664SU.rst |  2 ++
 3 files changed, 38 insertions(+), 1 deletion(-)
 mode change 100755 => 100644 Lib/uu.py
 create mode 100644 Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst

diff --git a/Lib/test/test_uu.py b/Lib/test/test_uu.py
index 0493aae4fc67be..a189d6bc4b05d3 100644
--- a/Lib/test/test_uu.py
+++ b/Lib/test/test_uu.py
@@ -147,6 +147,34 @@ def test_newlines_escaped(self):
         uu.encode(inp, out, filename)
         self.assertIn(safefilename, out.getvalue())
 
+    def test_no_directory_traversal(self):
+        relative_bad = b"""\
+begin 644 ../../../../../../../../tmp/test1
+$86)C"@``
+`
+end
+"""
+        with self.assertRaisesRegex(uu.Error, 'directory'):
+            uu.decode(io.BytesIO(relative_bad))
+        if os.altsep:
+            relative_bad_bs = relative_bad.replace(b'/', b'\\')
+            with self.assertRaisesRegex(uu.Error, 'directory'):
+                uu.decode(io.BytesIO(relative_bad_bs))
+
+        absolute_bad = b"""\
+begin 644 /tmp/test2
+$86)C"@``
+`
+end
+"""
+        with self.assertRaisesRegex(uu.Error, 'directory'):
+            uu.decode(io.BytesIO(absolute_bad))
+        if os.altsep:
+            absolute_bad_bs = absolute_bad.replace(b'/', b'\\')
+            with self.assertRaisesRegex(uu.Error, 'directory'):
+                uu.decode(io.BytesIO(absolute_bad_bs))
+
+
 class UUStdIOTest(unittest.TestCase):
 
     def setUp(self):
diff --git a/Lib/uu.py b/Lib/uu.py
old mode 100755
new mode 100644
index 6f8805d8c5d0c6..26bb59ae073ec5
--- a/Lib/uu.py
+++ b/Lib/uu.py
@@ -133,7 +133,14 @@ def decode(in_file, out_file=None, mode=None, quiet=False):
             # If the filename isn't ASCII, what's up with that?!?
             out_file = hdrfields[2].rstrip(b' \t\r\n\f').decode("ascii")
             if os.path.exists(out_file):
-                raise Error('Cannot overwrite existing file: %s' % out_file)
+                raise Error(f'Cannot overwrite existing file: {out_file}')
+            if (out_file.startswith(os.sep) or
+                f'..{os.sep}' in out_file or (
+                    os.altsep and
+                    (out_file.startswith(os.altsep) or
+                     f'..{os.altsep}' in out_file))
+               ):
+                raise Error(f'Refusing to write to {out_file} due to directory traversal')
         if mode is None:
             mode = int(hdrfields[1], 8)
         #
diff --git a/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst
new file mode 100644
index 00000000000000..b7002e81b6b677
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2023-05-02-17-56-32.gh-issue-99889.l664SU.rst
@@ -0,0 +1,2 @@
+Fixed a security in flaw in :func:`uu.decode` that could allow for
+directory traversal based on the input if no ``out_file`` was specified.

From c3b595e73efac59360d6dc869802abc752092460 Mon Sep 17 00:00:00 2001
From: Carl Meyer <carl@oddbird.net>
Date: Tue, 9 May 2023 11:02:14 -0600
Subject: [PATCH 34/35] gh-97933: (PEP 709) inline list/dict/set comprehensions
 (#101441)

Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
---
 Doc/library/dis.rst                           |   8 +
 Doc/whatsnew/3.12.rst                         |  24 +
 Include/internal/pycore_code.h                |   1 +
 Include/internal/pycore_compile.h             |   3 +
 Include/internal/pycore_flowgraph.h           |   2 +-
 Include/internal/pycore_opcode.h              |  13 +-
 Include/internal/pycore_symtable.h            |   1 +
 Include/opcode.h                              |  21 +-
 Lib/importlib/_bootstrap_external.py          |   3 +-
 Lib/opcode.py                                 |   4 +
 Lib/test/test_compile.py                      |  24 +-
 Lib/test/test_compiler_assemble.py            |   5 +-
 Lib/test/test_dis.py                          |  33 +-
 Lib/test/test_inspect.py                      |  10 +-
 Lib/test/test_listcomps.py                    | 275 ++++-
 Lib/test/test_trace.py                        |   4 +-
 ...3-01-30-15-40-29.gh-issue-97933.nUlp3r.rst |   2 +
 Modules/_testinternalcapi.c                   |   2 +
 Objects/frameobject.c                         |   4 +
 Python/assemble.c                             |   3 +
 Python/bytecodes.c                            |   6 +
 Python/compile.c                              | 363 +++++--
 Python/flowgraph.c                            |  16 +-
 Python/generated_cases.c.h                    | 962 +++++++++---------
 Python/opcode_metadata.h                      |   5 +
 Python/opcode_targets.h                       |   8 +-
 Python/symtable.c                             | 136 ++-
 27 files changed, 1243 insertions(+), 695 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst

diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 296d8a9c66faa4..248743b8fa0a87 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -1196,6 +1196,14 @@ iterations of the loop.
 
    .. versionadded:: 3.12
 
+.. opcode:: LOAD_FAST_AND_CLEAR (var_num)
+
+   Pushes a reference to the local ``co_varnames[var_num]`` onto the stack (or
+   pushes ``NULL`` onto the stack if the local variable has not been
+   initialized) and sets ``co_varnames[var_num]`` to ``NULL``.
+
+   .. versionadded:: 3.12
+
 .. opcode:: STORE_FAST (var_num)
 
    Stores ``STACK.pop()`` into the local ``co_varnames[var_num]``.
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 12d357f117b1b6..eb13d4bf031c95 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -153,6 +153,30 @@ New Features
   In Python 3.14, the default will switch to ``'data'``.
   (Contributed by Petr Viktorin in :pep:`706`.)
 
+.. _whatsnew312-pep709:
+
+PEP 709: Comprehension inlining
+-------------------------------
+
+Dictionary, list, and set comprehensions are now inlined, rather than creating a
+new single-use function object for each execution of the comprehension. This
+speeds up execution of a comprehension by up to 2x.
+
+Comprehension iteration variables remain isolated; they don't overwrite a
+variable of the same name in the outer scope, nor are they visible after the
+comprehension. This isolation is now maintained via stack/locals manipulation,
+not via separate function scope.
+
+Inlining does result in a few visible behavior changes:
+
+* There is no longer a separate frame for the comprehension in tracebacks,
+  and tracing/profiling no longer shows the comprehension as a function call.
+* Calling :func:`locals` inside a comprehension now includes variables
+  from outside the comprehension, and no longer includes the synthetic ``.0``
+  variable for the comprehension "argument".
+
+Contributed by Carl Meyer and Vladimir Matveev in :pep:`709`.
+
 PEP 688: Making the buffer protocol accessible in Python
 --------------------------------------------------------
 
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index 86fd48b63ef8e4..c1f017fdb753c5 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -131,6 +131,7 @@ struct callable_cache {
 // Note that these all fit within a byte, as do combinations.
 // Later, we will use the smaller numbers to differentiate the different
 // kinds of locals (e.g. pos-only arg, varkwargs, local-only).
+#define CO_FAST_HIDDEN  0x10
 #define CO_FAST_LOCAL   0x20
 #define CO_FAST_CELL    0x40
 #define CO_FAST_FREE    0x80
diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h
index d2b12c91fe7a00..499f55f3e276be 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -70,6 +70,9 @@ typedef struct {
     PyObject *u_varnames;  /* local variables */
     PyObject *u_cellvars;  /* cell variables */
     PyObject *u_freevars;  /* free variables */
+    PyObject *u_fasthidden; /* dict; keys are names that are fast-locals only
+                               temporarily within an inlined comprehension. When
+                               value is True, treat as fast-local. */
 
     Py_ssize_t u_argcount;        /* number of arguments for block */
     Py_ssize_t u_posonlyargcount;        /* number of positional only arguments for block */
diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h
index 883334f4b182eb..720feb18636959 100644
--- a/Include/internal/pycore_flowgraph.h
+++ b/Include/internal/pycore_flowgraph.h
@@ -94,7 +94,7 @@ _PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b);
 int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
                             int code_flags, int nlocals, int nparams, int firstlineno);
 int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags);
-void _PyCfg_ConvertExceptionHandlersToNops(_PyCfgBasicblock *entryblock);
+void _PyCfg_ConvertPseudoOps(_PyCfgBasicblock *entryblock);
 int _PyCfg_ResolveJumps(_PyCfgBuilder *g);
 
 
diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h
index a82885463ab2e9..52ee70a7bfdc54 100644
--- a/Include/internal/pycore_opcode.h
+++ b/Include/internal/pycore_opcode.h
@@ -173,6 +173,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
     [LOAD_CONST__LOAD_FAST] = LOAD_CONST,
     [LOAD_DEREF] = LOAD_DEREF,
     [LOAD_FAST] = LOAD_FAST,
+    [LOAD_FAST_AND_CLEAR] = LOAD_FAST_AND_CLEAR,
     [LOAD_FAST_CHECK] = LOAD_FAST_CHECK,
     [LOAD_FAST__LOAD_CONST] = LOAD_FAST,
     [LOAD_FAST__LOAD_FAST] = LOAD_FAST,
@@ -239,7 +240,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
 #endif   // NEED_OPCODE_TABLES
 
 #ifdef Py_DEBUG
-static const char *const _PyOpcode_OpName[266] = {
+static const char *const _PyOpcode_OpName[267] = {
     [CACHE] = "CACHE",
     [POP_TOP] = "POP_TOP",
     [PUSH_NULL] = "PUSH_NULL",
@@ -383,7 +384,7 @@ static const char *const _PyOpcode_OpName[266] = {
     [JUMP_BACKWARD] = "JUMP_BACKWARD",
     [LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR",
     [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
-    [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST",
+    [LOAD_FAST_AND_CLEAR] = "LOAD_FAST_AND_CLEAR",
     [EXTENDED_ARG] = "EXTENDED_ARG",
     [LIST_APPEND] = "LIST_APPEND",
     [SET_ADD] = "SET_ADD",
@@ -393,21 +394,21 @@ static const char *const _PyOpcode_OpName[266] = {
     [YIELD_VALUE] = "YIELD_VALUE",
     [RESUME] = "RESUME",
     [MATCH_CLASS] = "MATCH_CLASS",
+    [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST",
     [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
-    [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
     [FORMAT_VALUE] = "FORMAT_VALUE",
     [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
     [BUILD_STRING] = "BUILD_STRING",
+    [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
     [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
     [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
     [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
-    [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
     [LIST_EXTEND] = "LIST_EXTEND",
     [SET_UPDATE] = "SET_UPDATE",
     [DICT_MERGE] = "DICT_MERGE",
     [DICT_UPDATE] = "DICT_UPDATE",
+    [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
     [SEND_GEN] = "SEND_GEN",
-    [167] = "<167>",
     [168] = "<168>",
     [169] = "<169>",
     [170] = "<170>",
@@ -506,11 +507,11 @@ static const char *const _PyOpcode_OpName[266] = {
     [LOAD_SUPER_METHOD] = "LOAD_SUPER_METHOD",
     [LOAD_ZERO_SUPER_METHOD] = "LOAD_ZERO_SUPER_METHOD",
     [LOAD_ZERO_SUPER_ATTR] = "LOAD_ZERO_SUPER_ATTR",
+    [STORE_FAST_MAYBE_NULL] = "STORE_FAST_MAYBE_NULL",
 };
 #endif
 
 #define EXTRA_CASES \
-    case 167: \
     case 168: \
     case 169: \
     case 170: \
diff --git a/Include/internal/pycore_symtable.h b/Include/internal/pycore_symtable.h
index 512c4c931f73e4..9a005be5402c4e 100644
--- a/Include/internal/pycore_symtable.h
+++ b/Include/internal/pycore_symtable.h
@@ -64,6 +64,7 @@ typedef struct _symtable_entry {
     unsigned ste_needs_class_closure : 1; /* for class scopes, true if a
                                              closure over __class__
                                              should be created */
+    unsigned ste_comp_inlined : 1; /* true if this comprehension is inlined */
     unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */
     int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */
     int ste_lineno;          /* first line of block */
diff --git a/Include/opcode.h b/Include/opcode.h
index 37a9e9bffa4cb7..f6f4af8c793d8d 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -97,6 +97,7 @@ extern "C" {
 #define JUMP_BACKWARD                          140
 #define LOAD_SUPER_ATTR                        141
 #define CALL_FUNCTION_EX                       142
+#define LOAD_FAST_AND_CLEAR                    143
 #define EXTENDED_ARG                           144
 #define LIST_APPEND                            145
 #define SET_ADD                                146
@@ -146,7 +147,8 @@ extern "C" {
 #define LOAD_SUPER_METHOD                      263
 #define LOAD_ZERO_SUPER_METHOD                 264
 #define LOAD_ZERO_SUPER_ATTR                   265
-#define MAX_PSEUDO_OPCODE                      265
+#define STORE_FAST_MAYBE_NULL                  266
+#define MAX_PSEUDO_OPCODE                      266
 #define BINARY_OP_ADD_FLOAT                      6
 #define BINARY_OP_ADD_INT                        7
 #define BINARY_OP_ADD_UNICODE                    8
@@ -202,14 +204,14 @@ extern "C" {
 #define STORE_ATTR_INSTANCE_VALUE              111
 #define STORE_ATTR_SLOT                        112
 #define STORE_ATTR_WITH_HINT                   113
-#define STORE_FAST__LOAD_FAST                  143
-#define STORE_FAST__STORE_FAST                 153
-#define STORE_SUBSCR_DICT                      154
-#define STORE_SUBSCR_LIST_INT                  158
-#define UNPACK_SEQUENCE_LIST                   159
-#define UNPACK_SEQUENCE_TUPLE                  160
-#define UNPACK_SEQUENCE_TWO_TUPLE              161
-#define SEND_GEN                               166
+#define STORE_FAST__LOAD_FAST                  153
+#define STORE_FAST__STORE_FAST                 154
+#define STORE_SUBSCR_DICT                      158
+#define STORE_SUBSCR_LIST_INT                  159
+#define UNPACK_SEQUENCE_LIST                   160
+#define UNPACK_SEQUENCE_TUPLE                  161
+#define UNPACK_SEQUENCE_TWO_TUPLE              166
+#define SEND_GEN                               167
 
 #define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\
     || ((op) == JUMP) \
@@ -218,6 +220,7 @@ extern "C" {
     || ((op) == LOAD_SUPER_METHOD) \
     || ((op) == LOAD_ZERO_SUPER_METHOD) \
     || ((op) == LOAD_ZERO_SUPER_ATTR) \
+    || ((op) == STORE_FAST_MAYBE_NULL) \
     )
 
 #define HAS_CONST(op) (false\
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 7a3fdbaebdf24e..d4a1593db2c874 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -442,6 +442,7 @@ def _write_atomic(path, data, mode=0o666):
 #     Python 3.12b1 3526 (Add instrumentation support)
 #     Python 3.12b1 3527 (Add LOAD_SUPER_ATTR)
 #     Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization)
+#     Python 3.12b1 3529 (Inline list/dict/set comprehensions)
 
 #     Python 3.13 will start with 3550
 
@@ -458,7 +459,7 @@ def _write_atomic(path, data, mode=0o666):
 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
 # in PC/launcher.c must also be updated.
 
-MAGIC_NUMBER = (3528).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3529).to_bytes(2, 'little') + b'\r\n'
 
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
diff --git a/Lib/opcode.py b/Lib/opcode.py
index ad54bd27fba3d9..d6d478aa1f479d 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -198,6 +198,8 @@ def pseudo_op(name, op, real_ops):
 jrel_op('JUMP_BACKWARD', 140)    # Number of words to skip (backwards)
 name_op('LOAD_SUPER_ATTR', 141)
 def_op('CALL_FUNCTION_EX', 142)  # Flags
+def_op('LOAD_FAST_AND_CLEAR', 143)  # Local variable number
+haslocal.append(143)
 
 def_op('EXTENDED_ARG', 144)
 EXTENDED_ARG = 144
@@ -268,6 +270,8 @@ def pseudo_op(name, op, real_ops):
 pseudo_op('LOAD_ZERO_SUPER_METHOD', 264, ['LOAD_SUPER_ATTR'])
 pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR'])
 
+pseudo_op('STORE_FAST_MAYBE_NULL', 266, ['STORE_FAST'])
+
 MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1
 
 del def_op, name_op, jrel_op, jabs_op, pseudo_op
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index dca38418935b76..c68b9ce388466e 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -1352,14 +1352,11 @@ def test_multiline_list_comprehension(self):
                                and x != 50)]
             """)
         compiled_code, _ = self.check_positions_against_ast(snippet)
-        compiled_code = compiled_code.co_consts[0]
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND',
             line=1, end_line=2, column=1, end_column=8, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=1, end_line=2, column=1, end_column=8, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
-            line=1, end_line=6, column=0, end_column=32, occurrence=1)
 
     def test_multiline_async_list_comprehension(self):
         snippet = textwrap.dedent("""\
@@ -1374,13 +1371,13 @@ async def f():
         compiled_code, _ = self.check_positions_against_ast(snippet)
         g = {}
         eval(compiled_code, g)
-        compiled_code = g['f'].__code__.co_consts[1]
+        compiled_code = g['f'].__code__
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'LIST_APPEND',
             line=2, end_line=3, column=5, end_column=12, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=2, end_line=3, column=5, end_column=12, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
+        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
             line=2, end_line=7, column=4, end_column=36, occurrence=1)
 
     def test_multiline_set_comprehension(self):
@@ -1393,14 +1390,11 @@ def test_multiline_set_comprehension(self):
                                and x != 50)}
             """)
         compiled_code, _ = self.check_positions_against_ast(snippet)
-        compiled_code = compiled_code.co_consts[0]
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD',
             line=1, end_line=2, column=1, end_column=8, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=1, end_line=2, column=1, end_column=8, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
-            line=1, end_line=6, column=0, end_column=32, occurrence=1)
 
     def test_multiline_async_set_comprehension(self):
         snippet = textwrap.dedent("""\
@@ -1415,13 +1409,13 @@ async def f():
         compiled_code, _ = self.check_positions_against_ast(snippet)
         g = {}
         eval(compiled_code, g)
-        compiled_code = g['f'].__code__.co_consts[1]
+        compiled_code = g['f'].__code__
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'SET_ADD',
             line=2, end_line=3, column=5, end_column=12, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=2, end_line=3, column=5, end_column=12, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
+        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
             line=2, end_line=7, column=4, end_column=36, occurrence=1)
 
     def test_multiline_dict_comprehension(self):
@@ -1434,14 +1428,11 @@ def test_multiline_dict_comprehension(self):
                                and x != 50)}
             """)
         compiled_code, _ = self.check_positions_against_ast(snippet)
-        compiled_code = compiled_code.co_consts[0]
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD',
             line=1, end_line=2, column=1, end_column=7, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=1, end_line=2, column=1, end_column=7, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
-            line=1, end_line=6, column=0, end_column=32, occurrence=1)
 
     def test_multiline_async_dict_comprehension(self):
         snippet = textwrap.dedent("""\
@@ -1456,13 +1447,13 @@ async def f():
         compiled_code, _ = self.check_positions_against_ast(snippet)
         g = {}
         eval(compiled_code, g)
-        compiled_code = g['f'].__code__.co_consts[1]
+        compiled_code = g['f'].__code__
         self.assertIsInstance(compiled_code, types.CodeType)
         self.assertOpcodeSourcePositionIs(compiled_code, 'MAP_ADD',
             line=2, end_line=3, column=5, end_column=11, occurrence=1)
         self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
             line=2, end_line=3, column=5, end_column=11, occurrence=1)
-        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
+        self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
             line=2, end_line=7, column=4, end_column=36, occurrence=1)
 
     def test_matchcase_sequence(self):
@@ -1711,9 +1702,6 @@ def test_column_offset_deduplication(self):
         for source in [
             "lambda: a",
             "(a for b in c)",
-            "[a for b in c]",
-            "{a for b in c}",
-            "{a: b for c in d}",
         ]:
             with self.subTest(source):
                 code = compile(f"{source}, {source}", "<test>", "eval")
diff --git a/Lib/test/test_compiler_assemble.py b/Lib/test/test_compiler_assemble.py
index 0bd7a09b001c1d..3e2a127de728cd 100644
--- a/Lib/test/test_compiler_assemble.py
+++ b/Lib/test/test_compiler_assemble.py
@@ -16,7 +16,7 @@ def complete_metadata(self, metadata, filename="myfile.py"):
             metadata.setdefault(key, key)
         for key in ['consts']:
             metadata.setdefault(key, [])
-        for key in ['names', 'varnames', 'cellvars', 'freevars']:
+        for key in ['names', 'varnames', 'cellvars', 'freevars', 'fasthidden']:
             metadata.setdefault(key, {})
         for key in ['argcount', 'posonlyargcount', 'kwonlyargcount']:
             metadata.setdefault(key, 0)
@@ -33,6 +33,9 @@ def assemble_test(self, insts, metadata, expected):
 
         expected_metadata = {}
         for key, value in metadata.items():
+            if key == "fasthidden":
+                # not exposed on code object
+                continue
             if isinstance(value, list):
                 expected_metadata[key] = tuple(value)
             elif isinstance(value, dict):
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 2f5d67fde86170..c90702a408eb33 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -154,7 +154,7 @@ def bug708901():
 
 
 def bug1333982(x=[]):
-    assert 0, ([s for s in x] +
+    assert 0, ((s for s in x) +
               1)
     pass
 
@@ -162,7 +162,7 @@ def bug1333982(x=[]):
 %3d        RESUME                   0
 
 %3d        LOAD_ASSERTION_ERROR
-           LOAD_CONST               1 (<code object <listcomp> at 0x..., file "%s", line %d>)
+           LOAD_CONST               1 (<code object <genexpr> at 0x..., file "%s", line %d>)
            MAKE_FUNCTION            0
            LOAD_FAST                0 (x)
            GET_ITER
@@ -675,7 +675,7 @@ async def _co(x):
 def _h(y):
     def foo(x):
         '''funcdoc'''
-        return [x + z for z in y]
+        return list(x + z for z in y)
     return foo
 
 dis_nested_0 = """\
@@ -705,13 +705,15 @@ def foo(x):
 
 %3d        RESUME                   0
 
-%3d        LOAD_CLOSURE             0 (x)
+%3d        LOAD_GLOBAL              1 (NULL + list)
+           LOAD_CLOSURE             0 (x)
            BUILD_TUPLE              1
-           LOAD_CONST               1 (<code object <listcomp> at 0x..., file "%s", line %d>)
+           LOAD_CONST               1 (<code object <genexpr> at 0x..., file "%s", line %d>)
            MAKE_FUNCTION            8 (closure)
            LOAD_DEREF               1 (y)
            GET_ITER
            CALL                     0
+           CALL                     1
            RETURN_VALUE
 """ % (dis_nested_0,
        __file__,
@@ -723,21 +725,28 @@ def foo(x):
 )
 
 dis_nested_2 = """%s
-Disassembly of <code object <listcomp> at 0x..., file "%s", line %d>:
+Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>:
            COPY_FREE_VARS           1
 
-%3d        RESUME                   0
-           BUILD_LIST               0
+%3d        RETURN_GENERATOR
+           POP_TOP
+           RESUME                   0
            LOAD_FAST                0 (.0)
-        >> FOR_ITER                 7 (to 26)
+        >> FOR_ITER                 9 (to 32)
            STORE_FAST               1 (z)
            LOAD_DEREF               2 (x)
            LOAD_FAST                1 (z)
            BINARY_OP                0 (+)
-           LIST_APPEND              2
-           JUMP_BACKWARD            9 (to 8)
+           YIELD_VALUE              1
+           RESUME                   1
+           POP_TOP
+           JUMP_BACKWARD           11 (to 10)
         >> END_FOR
-           RETURN_VALUE
+           RETURN_CONST             0 (None)
+        >> CALL_INTRINSIC_1         3 (INTRINSIC_STOPITERATION_ERROR)
+           RERAISE                  1
+ExceptionTable:
+1 row
 """ % (dis_nested_1,
        __file__,
        _h.__code__.co_firstlineno + 3,
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index d2b2f3171e785d..364f75db908b05 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -4280,14 +4280,14 @@ def test(*args, **kwargs):
 
     @cpython_only
     def test_signature_bind_implicit_arg(self):
-        # Issue #19611: getcallargs should work with set comprehensions
+        # Issue #19611: getcallargs should work with comprehensions
         def make_set():
-            return {z * z for z in range(5)}
-        setcomp_code = make_set.__code__.co_consts[1]
-        setcomp_func = types.FunctionType(setcomp_code, {})
+            return set(z * z for z in range(5))
+        gencomp_code = make_set.__code__.co_consts[1]
+        gencomp_func = types.FunctionType(gencomp_code, {})
 
         iterator = iter(range(5))
-        self.assertEqual(self.call(setcomp_func, iterator), {0, 1, 4, 9, 16})
+        self.assertEqual(set(self.call(gencomp_func, iterator)), {0, 1, 4, 9, 16})
 
     def test_signature_bind_posonly_kwargs(self):
         def foo(bar, /, **kwargs):
diff --git a/Lib/test/test_listcomps.py b/Lib/test/test_listcomps.py
index 91bf2547edc4ae..92fed98dd0004a 100644
--- a/Lib/test/test_listcomps.py
+++ b/Lib/test/test_listcomps.py
@@ -1,4 +1,5 @@
 import doctest
+import textwrap
 import unittest
 
 
@@ -87,63 +88,227 @@
     >>> [None for i in range(10)]
     [None, None, None, None, None, None, None, None, None, None]
 
-########### Tests for various scoping corner cases ############
-
-Return lambdas that use the iteration variable as a default argument
-
-    >>> items = [(lambda i=i: i) for i in range(5)]
-    >>> [x() for x in items]
-    [0, 1, 2, 3, 4]
-
-Same again, only this time as a closure variable
-
-    >>> items = [(lambda: i) for i in range(5)]
-    >>> [x() for x in items]
-    [4, 4, 4, 4, 4]
-
-Another way to test that the iteration variable is local to the list comp
-
-    >>> items = [(lambda: i) for i in range(5)]
-    >>> i = 20
-    >>> [x() for x in items]
-    [4, 4, 4, 4, 4]
-
-And confirm that a closure can jump over the list comp scope
-
-    >>> items = [(lambda: y) for i in range(5)]
-    >>> y = 2
-    >>> [x() for x in items]
-    [2, 2, 2, 2, 2]
-
-We also repeat each of the above scoping tests inside a function
-
-    >>> def test_func():
-    ...     items = [(lambda i=i: i) for i in range(5)]
-    ...     return [x() for x in items]
-    >>> test_func()
-    [0, 1, 2, 3, 4]
+"""
 
-    >>> def test_func():
-    ...     items = [(lambda: i) for i in range(5)]
-    ...     return [x() for x in items]
-    >>> test_func()
-    [4, 4, 4, 4, 4]
-
-    >>> def test_func():
-    ...     items = [(lambda: i) for i in range(5)]
-    ...     i = 20
-    ...     return [x() for x in items]
-    >>> test_func()
-    [4, 4, 4, 4, 4]
-
-    >>> def test_func():
-    ...     items = [(lambda: y) for i in range(5)]
-    ...     y = 2
-    ...     return [x() for x in items]
-    >>> test_func()
-    [2, 2, 2, 2, 2]
 
-"""
+class ListComprehensionTest(unittest.TestCase):
+    def _check_in_scopes(self, code, outputs=None, ns=None, scopes=None, raises=()):
+        code = textwrap.dedent(code)
+        scopes = scopes or ["module", "class", "function"]
+        for scope in scopes:
+            with self.subTest(scope=scope):
+                if scope == "class":
+                    newcode = textwrap.dedent("""
+                        class _C:
+                            {code}
+                    """).format(code=textwrap.indent(code, "    "))
+                    def get_output(moddict, name):
+                        return getattr(moddict["_C"], name)
+                elif scope == "function":
+                    newcode = textwrap.dedent("""
+                        def _f():
+                            {code}
+                            return locals()
+                        _out = _f()
+                    """).format(code=textwrap.indent(code, "    "))
+                    def get_output(moddict, name):
+                        return moddict["_out"][name]
+                else:
+                    newcode = code
+                    def get_output(moddict, name):
+                        return moddict[name]
+                ns = ns or {}
+                try:
+                    exec(newcode, ns)
+                except raises as e:
+                    # We care about e.g. NameError vs UnboundLocalError
+                    self.assertIs(type(e), raises)
+                else:
+                    for k, v in (outputs or {}).items():
+                        self.assertEqual(get_output(ns, k), v)
+
+    def test_lambdas_with_iteration_var_as_default(self):
+        code = """
+            items = [(lambda i=i: i) for i in range(5)]
+            y = [x() for x in items]
+        """
+        outputs = {"y": [0, 1, 2, 3, 4]}
+        self._check_in_scopes(code, outputs)
+
+    def test_lambdas_with_free_var(self):
+        code = """
+            items = [(lambda: i) for i in range(5)]
+            y = [x() for x in items]
+        """
+        outputs = {"y": [4, 4, 4, 4, 4]}
+        self._check_in_scopes(code, outputs)
+
+    def test_class_scope_free_var_with_class_cell(self):
+        class C:
+            def method(self):
+                super()
+                return __class__
+            items = [(lambda: i) for i in range(5)]
+            y = [x() for x in items]
+
+        self.assertEqual(C.y, [4, 4, 4, 4, 4])
+        self.assertIs(C().method(), C)
+
+    def test_inner_cell_shadows_outer(self):
+        code = """
+            items = [(lambda: i) for i in range(5)]
+            i = 20
+            y = [x() for x in items]
+        """
+        outputs = {"y": [4, 4, 4, 4, 4], "i": 20}
+        self._check_in_scopes(code, outputs)
+
+    def test_closure_can_jump_over_comp_scope(self):
+        code = """
+            items = [(lambda: y) for i in range(5)]
+            y = 2
+            z = [x() for x in items]
+        """
+        outputs = {"z": [2, 2, 2, 2, 2]}
+        self._check_in_scopes(code, outputs)
+
+    def test_inner_cell_shadows_outer_redefined(self):
+        code = """
+            y = 10
+            items = [(lambda: y) for y in range(5)]
+            x = y
+            y = 20
+            out = [z() for z in items]
+        """
+        outputs = {"x": 10, "out": [4, 4, 4, 4, 4]}
+        self._check_in_scopes(code, outputs)
+
+    def test_shadows_outer_cell(self):
+        code = """
+            def inner():
+                return g
+            [g for g in range(5)]
+            x = inner()
+        """
+        outputs = {"x": -1}
+        self._check_in_scopes(code, outputs, ns={"g": -1})
+
+    def test_assignment_expression(self):
+        code = """
+            x = -1
+            items = [(x:=y) for y in range(3)]
+        """
+        outputs = {"x": 2}
+        # assignment expression in comprehension is disallowed in class scope
+        self._check_in_scopes(code, outputs, scopes=["module", "function"])
+
+    def test_free_var_in_comp_child(self):
+        code = """
+            lst = range(3)
+            funcs = [lambda: x for x in lst]
+            inc = [x + 1 for x in lst]
+            [x for x in inc]
+            x = funcs[0]()
+        """
+        outputs = {"x": 2}
+        self._check_in_scopes(code, outputs)
+
+    def test_shadow_with_free_and_local(self):
+        code = """
+            lst = range(3)
+            x = -1
+            funcs = [lambda: x for x in lst]
+            items = [x + 1 for x in lst]
+        """
+        outputs = {"x": -1}
+        self._check_in_scopes(code, outputs)
+
+    def test_shadow_comp_iterable_name(self):
+        code = """
+            x = [1]
+            y = [x for x in x]
+        """
+        outputs = {"x": [1]}
+        self._check_in_scopes(code, outputs)
+
+    def test_nested_free(self):
+        code = """
+            x = 1
+            def g():
+                [x for x in range(3)]
+                return x
+            g()
+        """
+        outputs = {"x": 1}
+        self._check_in_scopes(code, outputs)
+
+    def test_introspecting_frame_locals(self):
+        code = """
+            import sys
+            [i for i in range(2)]
+            i = 20
+            sys._getframe().f_locals
+        """
+        outputs = {"i": 20}
+        self._check_in_scopes(code, outputs)
+
+    def test_nested(self):
+        code = """
+            l = [2, 3]
+            y = [[x ** 2 for x in range(x)] for x in l]
+        """
+        outputs = {"y": [[0, 1], [0, 1, 4]]}
+        self._check_in_scopes(code, outputs)
+
+    def test_nested_2(self):
+        code = """
+            l = [1, 2, 3]
+            x = 3
+            y = [x for [x ** x for x in range(x)][x - 1] in l]
+        """
+        outputs = {"y": [3, 3, 3]}
+        self._check_in_scopes(code, outputs)
+
+    def test_nested_3(self):
+        code = """
+            l = [(1, 2), (3, 4), (5, 6)]
+            y = [x for (x, [x ** x for x in range(x)][x - 1]) in l]
+        """
+        outputs = {"y": [1, 3, 5]}
+        self._check_in_scopes(code, outputs)
+
+    def test_nameerror(self):
+        code = """
+            [x for x in [1]]
+            x
+        """
+
+        self._check_in_scopes(code, raises=NameError)
+
+    def test_dunder_name(self):
+        code = """
+            y = [__x for __x in [1]]
+        """
+        outputs = {"y": [1]}
+        self._check_in_scopes(code, outputs)
+
+    def test_unbound_local_after_comprehension(self):
+        def f():
+            if False:
+                x = 0
+            [x for x in [1]]
+            return x
+
+        with self.assertRaises(UnboundLocalError):
+            f()
+
+    def test_unbound_local_inside_comprehension(self):
+        def f():
+            l = [None]
+            return [1 for (l[0], l) in [[1, 2]]]
+
+        with self.assertRaises(UnboundLocalError):
+            f()
 
 
 __test__ = {'doctests' : doctests}
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
index fad2b3b8379ffc..73339ebdb7c4e9 100644
--- a/Lib/test/test_trace.py
+++ b/Lib/test/test_trace.py
@@ -187,9 +187,7 @@ def test_trace_list_comprehension(self):
         firstlineno_called = get_firstlineno(traced_doubler)
         expected = {
             (self.my_py_filename, firstlineno_calling + 1): 1,
-            # List comprehensions work differently in 3.x, so the count
-            # below changed compared to 2.x.
-            (self.my_py_filename, firstlineno_calling + 2): 12,
+            (self.my_py_filename, firstlineno_calling + 2): 11,
             (self.my_py_filename, firstlineno_calling + 3): 1,
             (self.my_py_filename, firstlineno_called + 1): 10,
         }
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst b/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst
new file mode 100644
index 00000000000000..2eec05cb3ace5c
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-01-30-15-40-29.gh-issue-97933.nUlp3r.rst	
@@ -0,0 +1,2 @@
+:pep:`709`: inline list, dict and set comprehensions to improve performance
+and reduce bytecode size.
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 8009dca3d0b746..ea9b6e72b3c924 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -669,12 +669,14 @@ _testinternalcapi_assemble_code_object_impl(PyObject *module,
     umd.u_varnames = PyDict_GetItemString(metadata, "varnames");
     umd.u_cellvars = PyDict_GetItemString(metadata, "cellvars");
     umd.u_freevars = PyDict_GetItemString(metadata, "freevars");
+    umd.u_fasthidden = PyDict_GetItemString(metadata, "fasthidden");
 
     assert(PyDict_Check(umd.u_consts));
     assert(PyDict_Check(umd.u_names));
     assert(PyDict_Check(umd.u_varnames));
     assert(PyDict_Check(umd.u_cellvars));
     assert(PyDict_Check(umd.u_freevars));
+    assert(PyDict_Check(umd.u_fasthidden));
 
     umd.u_argcount = get_nonnegative_int_from_dict(metadata, "argcount");
     umd.u_posonlyargcount = get_nonnegative_int_from_dict(metadata, "posonlyargcount");
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index d0eca447c012ea..d9aaea7831a380 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -1224,6 +1224,10 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame)
         }
 
         PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
+        _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
+        if (kind & CO_FAST_HIDDEN) {
+            continue;
+        }
         if (value == NULL) {
             if (PyObject_DelItem(locals, name) != 0) {
                 if (PyErr_ExceptionMatches(PyExc_KeyError)) {
diff --git a/Python/assemble.c b/Python/assemble.c
index 369dd8dcde9b9b..6889831ae3fe0c 100644
--- a/Python/assemble.c
+++ b/Python/assemble.c
@@ -456,6 +456,9 @@ compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
         assert(offset < nlocalsplus);
         // For now we do not distinguish arg kinds.
         _PyLocals_Kind kind = CO_FAST_LOCAL;
+        if (PyDict_Contains(umd->u_fasthidden, k)) {
+            kind |= CO_FAST_HIDDEN;
+        }
         if (PyDict_GetItem(umd->u_cellvars, k) != NULL) {
             kind |= CO_FAST_CELL;
         }
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index e83894e8902872..82c10044418345 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -194,6 +194,12 @@ dummy_func(
             Py_INCREF(value);
         }
 
+        inst(LOAD_FAST_AND_CLEAR, (-- value)) {
+            value = GETLOCAL(oparg);
+            // do not use SETLOCAL here, it decrefs the old value
+            GETLOCAL(oparg) = NULL;
+        }
+
         inst(LOAD_CONST, (-- value)) {
             value = GETITEM(frame->f_code->co_consts, oparg);
             Py_INCREF(value);
diff --git a/Python/compile.c b/Python/compile.c
index 12ae831361963d..941c6e9d4fdbb7 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -381,7 +381,6 @@ struct compiler_unit {
 
     int u_scope_type;
 
-
     PyObject *u_private;        /* for private name mangling */
 
     instr_sequence u_instr_sequence; /* codegen output */
@@ -485,13 +484,15 @@ static int compiler_sync_comprehension_generator(
                                       struct compiler *c, location loc,
                                       asdl_comprehension_seq *generators, int gen_index,
                                       int depth,
-                                      expr_ty elt, expr_ty val, int type);
+                                      expr_ty elt, expr_ty val, int type,
+                                      int iter_on_stack);
 
 static int compiler_async_comprehension_generator(
                                       struct compiler *c, location loc,
                                       asdl_comprehension_seq *generators, int gen_index,
                                       int depth,
-                                      expr_ty elt, expr_ty val, int type);
+                                      expr_ty elt, expr_ty val, int type,
+                                      int iter_on_stack);
 
 static int compiler_pattern(struct compiler *, pattern_ty, pattern_context *);
 static int compiler_match(struct compiler *, stmt_ty);
@@ -689,6 +690,7 @@ compiler_unit_free(struct compiler_unit *u)
     Py_CLEAR(u->u_metadata.u_varnames);
     Py_CLEAR(u->u_metadata.u_freevars);
     Py_CLEAR(u->u_metadata.u_cellvars);
+    Py_CLEAR(u->u_metadata.u_fasthidden);
     Py_CLEAR(u->u_private);
     PyObject_Free(u);
 }
@@ -837,6 +839,8 @@ stack_effect(int opcode, int oparg, int jump)
              * if an exception be raised. */
             return jump ? 1 : 0;
 
+        case STORE_FAST_MAYBE_NULL:
+            return -1;
         case LOAD_METHOD:
             return 1;
         case LOAD_SUPER_METHOD:
@@ -1239,11 +1243,9 @@ compiler_enter_scope(struct compiler *c, identifier name,
     }
     if (u->u_ste->ste_needs_class_closure) {
         /* Cook up an implicit __class__ cell. */
-        int res;
+        Py_ssize_t res;
         assert(u->u_scope_type == COMPILER_SCOPE_CLASS);
-        assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) == 0);
-        res = PyDict_SetItem(u->u_metadata.u_cellvars, &_Py_ID(__class__),
-                             _PyLong_GetZero());
+        res = dict_add_o(u->u_metadata.u_cellvars, &_Py_ID(__class__));
         if (res < 0) {
             compiler_unit_free(u);
             return ERROR;
@@ -1257,6 +1259,12 @@ compiler_enter_scope(struct compiler *c, identifier name,
         return ERROR;
     }
 
+    u->u_metadata.u_fasthidden = PyDict_New();
+    if (!u->u_metadata.u_fasthidden) {
+        compiler_unit_free(u);
+        return ERROR;
+    }
+
     u->u_nfblocks = 0;
     u->u_metadata.u_firstlineno = lineno;
     u->u_metadata.u_consts = PyDict_New();
@@ -2235,7 +2243,6 @@ compiler_class(struct compiler *c, stmt_ty s)
                 compiler_exit_scope(c);
                 return ERROR;
             }
-            assert(i == 0);
             ADDOP_I(c, NO_LOCATION, LOAD_CLOSURE, i);
             ADDOP_I(c, NO_LOCATION, COPY, 1);
             if (compiler_nameop(c, NO_LOCATION, &_Py_ID(__classcell__), Store) < 0) {
@@ -2245,7 +2252,6 @@ compiler_class(struct compiler *c, stmt_ty s)
         }
         else {
             /* No methods referenced __class__, so just return None */
-            assert(PyDict_GET_SIZE(c->u->u_metadata.u_cellvars) == 0);
             ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
         }
         ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE);
@@ -3718,7 +3724,8 @@ compiler_nameop(struct compiler *c, location loc,
         optype = OP_DEREF;
         break;
     case LOCAL:
-        if (c->u->u_ste->ste_type == FunctionBlock)
+        if (c->u->u_ste->ste_type == FunctionBlock ||
+                (PyDict_GetItem(c->u->u_metadata.u_fasthidden, mangled) == Py_True))
             optype = OP_FAST;
         break;
     case GLOBAL_IMPLICIT:
@@ -4742,16 +4749,19 @@ static int
 compiler_comprehension_generator(struct compiler *c, location loc,
                                  asdl_comprehension_seq *generators, int gen_index,
                                  int depth,
-                                 expr_ty elt, expr_ty val, int type)
+                                 expr_ty elt, expr_ty val, int type,
+                                 int iter_on_stack)
 {
     comprehension_ty gen;
     gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
     if (gen->is_async) {
         return compiler_async_comprehension_generator(
-            c, loc, generators, gen_index, depth, elt, val, type);
+            c, loc, generators, gen_index, depth, elt, val, type,
+            iter_on_stack);
     } else {
         return compiler_sync_comprehension_generator(
-            c, loc, generators, gen_index, depth, elt, val, type);
+            c, loc, generators, gen_index, depth, elt, val, type,
+            iter_on_stack);
     }
 }
 
@@ -4759,7 +4769,8 @@ static int
 compiler_sync_comprehension_generator(struct compiler *c, location loc,
                                       asdl_comprehension_seq *generators,
                                       int gen_index, int depth,
-                                      expr_ty elt, expr_ty val, int type)
+                                      expr_ty elt, expr_ty val, int type,
+                                      int iter_on_stack)
 {
     /* generate code for the iterator, then each of the ifs,
        and then write to the element */
@@ -4771,37 +4782,39 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
     comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators,
                                                           gen_index);
 
-    if (gen_index == 0) {
-        /* Receive outermost iter as an implicit argument */
-        c->u->u_metadata.u_argcount = 1;
-        ADDOP_I(c, loc, LOAD_FAST, 0);
-    }
-    else {
-        /* Sub-iter - calculate on the fly */
-        /* Fast path for the temporary variable assignment idiom:
-             for y in [f(x)]
-         */
-        asdl_expr_seq *elts;
-        switch (gen->iter->kind) {
-            case List_kind:
-                elts = gen->iter->v.List.elts;
-                break;
-            case Tuple_kind:
-                elts = gen->iter->v.Tuple.elts;
-                break;
-            default:
-                elts = NULL;
-        }
-        if (asdl_seq_LEN(elts) == 1) {
-            expr_ty elt = asdl_seq_GET(elts, 0);
-            if (elt->kind != Starred_kind) {
-                VISIT(c, expr, elt);
-                start = NO_LABEL;
-            }
+    if (!iter_on_stack) {
+        if (gen_index == 0) {
+            /* Receive outermost iter as an implicit argument */
+            c->u->u_metadata.u_argcount = 1;
+            ADDOP_I(c, loc, LOAD_FAST, 0);
         }
-        if (IS_LABEL(start)) {
-            VISIT(c, expr, gen->iter);
-            ADDOP(c, loc, GET_ITER);
+        else {
+            /* Sub-iter - calculate on the fly */
+            /* Fast path for the temporary variable assignment idiom:
+                for y in [f(x)]
+            */
+            asdl_expr_seq *elts;
+            switch (gen->iter->kind) {
+                case List_kind:
+                    elts = gen->iter->v.List.elts;
+                    break;
+                case Tuple_kind:
+                    elts = gen->iter->v.Tuple.elts;
+                    break;
+                default:
+                    elts = NULL;
+            }
+            if (asdl_seq_LEN(elts) == 1) {
+                expr_ty elt = asdl_seq_GET(elts, 0);
+                if (elt->kind != Starred_kind) {
+                    VISIT(c, expr, elt);
+                    start = NO_LABEL;
+                }
+            }
+            if (IS_LABEL(start)) {
+                VISIT(c, expr, gen->iter);
+                ADDOP(c, loc, GET_ITER);
+            }
         }
     }
     if (IS_LABEL(start)) {
@@ -4822,7 +4835,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
         RETURN_IF_ERROR(
             compiler_comprehension_generator(c, loc,
                                              generators, gen_index, depth,
-                                             elt, val, type));
+                                             elt, val, type, 0));
     }
 
     location elt_loc = LOC(elt);
@@ -4875,7 +4888,8 @@ static int
 compiler_async_comprehension_generator(struct compiler *c, location loc,
                                       asdl_comprehension_seq *generators,
                                       int gen_index, int depth,
-                                      expr_ty elt, expr_ty val, int type)
+                                      expr_ty elt, expr_ty val, int type,
+                                      int iter_on_stack)
 {
     NEW_JUMP_TARGET_LABEL(c, start);
     NEW_JUMP_TARGET_LABEL(c, except);
@@ -4884,15 +4898,17 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
     comprehension_ty gen = (comprehension_ty)asdl_seq_GET(generators,
                                                           gen_index);
 
-    if (gen_index == 0) {
-        /* Receive outermost iter as an implicit argument */
-        c->u->u_metadata.u_argcount = 1;
-        ADDOP_I(c, loc, LOAD_FAST, 0);
-    }
-    else {
-        /* Sub-iter - calculate on the fly */
-        VISIT(c, expr, gen->iter);
-        ADDOP(c, loc, GET_AITER);
+    if (!iter_on_stack) {
+        if (gen_index == 0) {
+            /* Receive outermost iter as an implicit argument */
+            c->u->u_metadata.u_argcount = 1;
+            ADDOP_I(c, loc, LOAD_FAST, 0);
+        }
+        else {
+            /* Sub-iter - calculate on the fly */
+            VISIT(c, expr, gen->iter);
+            ADDOP(c, loc, GET_AITER);
+        }
     }
 
     USE_LABEL(c, start);
@@ -4919,7 +4935,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
         RETURN_IF_ERROR(
             compiler_comprehension_generator(c, loc,
                                              generators, gen_index, depth,
-                                             elt, val, type));
+                                             elt, val, type, 0));
     }
 
     location elt_loc = LOC(elt);
@@ -4968,26 +4984,212 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
     return SUCCESS;
 }
 
+typedef struct {
+    PyObject *pushed_locals;
+    PyObject *temp_symbols;
+    PyObject *fast_hidden;
+} inlined_comprehension_state;
+
+static int
+push_inlined_comprehension_state(struct compiler *c, location loc,
+                                 PySTEntryObject *entry,
+                                 inlined_comprehension_state *state)
+{
+    // iterate over names bound in the comprehension and ensure we isolate
+    // them from the outer scope as needed
+    PyObject *k, *v;
+    Py_ssize_t pos = 0;
+    while (PyDict_Next(entry->ste_symbols, &pos, &k, &v)) {
+        assert(PyLong_Check(v));
+        long symbol = PyLong_AS_LONG(v);
+        // only values bound in the comprehension (DEF_LOCAL) need to be handled
+        // at all; DEF_LOCAL | DEF_NONLOCAL can occur in the case of an
+        // assignment expression to a nonlocal in the comprehension, these don't
+        // need handling here since they shouldn't be isolated
+        if (symbol & DEF_LOCAL && !(symbol & DEF_NONLOCAL)) {
+            if (c->u->u_ste->ste_type != FunctionBlock) {
+                // non-function scope: override this name to use fast locals
+                PyObject *orig = PyDict_GetItem(c->u->u_metadata.u_fasthidden, k);
+                if (orig != Py_True) {
+                    if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_True) < 0) {
+                        return ERROR;
+                    }
+                    if (state->fast_hidden == NULL) {
+                        state->fast_hidden = PySet_New(NULL);
+                        if (state->fast_hidden == NULL) {
+                            return ERROR;
+                        }
+                    }
+                    if (PySet_Add(state->fast_hidden, k) < 0) {
+                        return ERROR;
+                    }
+                }
+            }
+            long scope = (symbol >> SCOPE_OFFSET) & SCOPE_MASK;
+            PyObject *outv = PyDict_GetItemWithError(c->u->u_ste->ste_symbols, k);
+            if (outv == NULL) {
+                return ERROR;
+            }
+            assert(PyLong_Check(outv));
+            long outsc = (PyLong_AS_LONG(outv) >> SCOPE_OFFSET) & SCOPE_MASK;
+            if (scope != outsc) {
+                // If a name has different scope inside than outside the
+                // comprehension, we need to temporarily handle it with the
+                // right scope while compiling the comprehension.
+                if (state->temp_symbols == NULL) {
+                    state->temp_symbols = PyDict_New();
+                    if (state->temp_symbols == NULL) {
+                        return ERROR;
+                    }
+                }
+                // update the symbol to the in-comprehension version and save
+                // the outer version; we'll restore it after running the
+                // comprehension
+                Py_INCREF(outv);
+                if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v) < 0) {
+                    Py_DECREF(outv);
+                    return ERROR;
+                }
+                if (PyDict_SetItem(state->temp_symbols, k, outv) < 0) {
+                    Py_DECREF(outv);
+                    return ERROR;
+                }
+                Py_DECREF(outv);
+            }
+            if (outsc == LOCAL || outsc == CELL || outsc == FREE) {
+                // local names bound in comprehension must be isolated from
+                // outer scope; push existing value (which may be NULL if
+                // not defined) on stack
+                if (state->pushed_locals == NULL) {
+                    state->pushed_locals = PyList_New(0);
+                    if (state->pushed_locals == NULL) {
+                        return ERROR;
+                    }
+                }
+                // in the case of a cell, this will actually push the cell
+                // itself to the stack, then we'll create a new one for the
+                // comprehension and restore the original one after
+                ADDOP_NAME(c, loc, LOAD_FAST_AND_CLEAR, k, varnames);
+                if (scope == CELL) {
+                    ADDOP_NAME(c, loc, MAKE_CELL, k, cellvars);
+                }
+                if (PyList_Append(state->pushed_locals, k) < 0) {
+                    return ERROR;
+                }
+            }
+        }
+    }
+    if (state->pushed_locals) {
+        // Outermost iterable expression was already evaluated and is on the
+        // stack, we need to swap it back to TOS. This also rotates the order of
+        // `pushed_locals` on the stack, but this will be reversed when we swap
+        // out the comprehension result in pop_inlined_comprehension_state
+        ADDOP_I(c, loc, SWAP, PyList_GET_SIZE(state->pushed_locals) + 1);
+    }
+
+    return SUCCESS;
+}
+
+static int
+pop_inlined_comprehension_state(struct compiler *c, location loc,
+                                inlined_comprehension_state state)
+{
+    PyObject *k, *v;
+    Py_ssize_t pos = 0;
+    if (state.temp_symbols) {
+        while (PyDict_Next(state.temp_symbols, &pos, &k, &v)) {
+            if (PyDict_SetItem(c->u->u_ste->ste_symbols, k, v)) {
+                return ERROR;
+            }
+        }
+        Py_CLEAR(state.temp_symbols);
+    }
+    if (state.pushed_locals) {
+        // pop names we pushed to stack earlier
+        Py_ssize_t npops = PyList_GET_SIZE(state.pushed_locals);
+        // Preserve the list/dict/set result of the comprehension as TOS. This
+        // reverses the SWAP we did in push_inlined_comprehension_state to get
+        // the outermost iterable to TOS, so we can still just iterate
+        // pushed_locals in simple reverse order
+        ADDOP_I(c, loc, SWAP, npops + 1);
+        for (Py_ssize_t i = npops - 1; i >= 0; --i) {
+            k = PyList_GetItem(state.pushed_locals, i);
+            if (k == NULL) {
+                return ERROR;
+            }
+            ADDOP_NAME(c, loc, STORE_FAST_MAYBE_NULL, k, varnames);
+        }
+        Py_CLEAR(state.pushed_locals);
+    }
+    if (state.fast_hidden) {
+        while (PySet_Size(state.fast_hidden) > 0) {
+            PyObject *k = PySet_Pop(state.fast_hidden);
+            if (k == NULL) {
+                return ERROR;
+            }
+            // we set to False instead of clearing, so we can track which names
+            // were temporarily fast-locals and should use CO_FAST_HIDDEN
+            if (PyDict_SetItem(c->u->u_metadata.u_fasthidden, k, Py_False)) {
+                Py_DECREF(k);
+                return ERROR;
+            }
+            Py_DECREF(k);
+        }
+        Py_CLEAR(state.fast_hidden);
+    }
+    return SUCCESS;
+}
+
+static inline int
+compiler_comprehension_iter(struct compiler *c, location loc,
+                            comprehension_ty comp)
+{
+    VISIT(c, expr, comp->iter);
+    if (comp->is_async) {
+        ADDOP(c, loc, GET_AITER);
+    }
+    else {
+        ADDOP(c, loc, GET_ITER);
+    }
+    return SUCCESS;
+}
+
 static int
 compiler_comprehension(struct compiler *c, expr_ty e, int type,
                        identifier name, asdl_comprehension_seq *generators, expr_ty elt,
                        expr_ty val)
 {
     PyCodeObject *co = NULL;
+    inlined_comprehension_state inline_state = {NULL, NULL};
     comprehension_ty outermost;
     int scope_type = c->u->u_scope_type;
-    int is_async_generator = 0;
     int is_top_level_await = IS_TOP_LEVEL_AWAIT(c);
-
-    outermost = (comprehension_ty) asdl_seq_GET(generators, 0);
-    if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION,
-                             (void *)e, e->lineno) < 0)
-    {
+    PySTEntryObject *entry = PySymtable_Lookup(c->c_st, (void *)e);
+    if (entry == NULL) {
         goto error;
     }
+    int is_inlined = entry->ste_comp_inlined;
+    int is_async_generator = entry->ste_coroutine;
+
     location loc = LOC(e);
 
-    is_async_generator = c->u->u_ste->ste_coroutine;
+    outermost = (comprehension_ty) asdl_seq_GET(generators, 0);
+    if (is_inlined) {
+        if (compiler_comprehension_iter(c, loc, outermost)) {
+            goto error;
+        }
+        if (push_inlined_comprehension_state(c, loc, entry, &inline_state)) {
+            goto error;
+        }
+    }
+    else {
+        if (compiler_enter_scope(c, name, COMPILER_SCOPE_COMPREHENSION,
+                                (void *)e, e->lineno) < 0)
+        {
+            goto error;
+        }
+    }
+    Py_CLEAR(entry);
 
     if (is_async_generator && type != COMP_GENEXP &&
         scope_type != COMPILER_SCOPE_ASYNC_FUNCTION &&
@@ -5018,13 +5220,23 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
         }
 
         ADDOP_I(c, loc, op, 0);
+        if (is_inlined) {
+            ADDOP_I(c, loc, SWAP, 2);
+        }
     }
 
     if (compiler_comprehension_generator(c, loc, generators, 0, 0,
-                                         elt, val, type) < 0) {
+                                         elt, val, type, is_inlined) < 0) {
         goto error_in_scope;
     }
 
+    if (is_inlined) {
+        if (pop_inlined_comprehension_state(c, loc, inline_state)) {
+            goto error;
+        }
+        return SUCCESS;
+    }
+
     if (type != COMP_GENEXP) {
         ADDOP(c, LOC(e), RETURN_VALUE);
     }
@@ -5047,15 +5259,10 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
     if (compiler_make_closure(c, loc, co, 0) < 0) {
         goto error;
     }
-    Py_DECREF(co);
+    Py_CLEAR(co);
 
-    VISIT(c, expr, outermost->iter);
-
-    loc = LOC(e);
-    if (outermost->is_async) {
-        ADDOP(c, loc, GET_AITER);
-    } else {
-        ADDOP(c, loc, GET_ITER);
+    if (compiler_comprehension_iter(c, loc, outermost)) {
+        goto error;
     }
 
     ADDOP_I(c, loc, CALL, 0);
@@ -5068,9 +5275,15 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
 
     return SUCCESS;
 error_in_scope:
-    compiler_exit_scope(c);
+    if (!is_inlined) {
+        compiler_exit_scope(c);
+    }
 error:
     Py_XDECREF(co);
+    Py_XDECREF(entry);
+    Py_XDECREF(inline_state.pushed_locals);
+    Py_XDECREF(inline_state.temp_symbols);
+    Py_XDECREF(inline_state.fast_hidden);
     return ERROR;
 }
 
@@ -6989,7 +7202,7 @@ optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
         goto error;
     }
 
-    _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock);
+    _PyCfg_ConvertPseudoOps(g.g_entryblock);
 
     /* Order of basic blocks must have been determined by now */
 
@@ -7401,7 +7614,7 @@ _PyCompile_Assemble(_PyCompile_CodeUnitMetadata *umd, PyObject *filename,
         goto error;
     }
 
-    _PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock);
+    _PyCfg_ConvertPseudoOps(g.g_entryblock);
 
     /* Order of basic blocks must have been determined by now */
 
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index f79afb4c66cd8b..7f790b79d2844f 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -1289,7 +1289,9 @@ swaptimize(basicblock *block, int *ix)
 // - can't invoke arbitrary code (besides finalizers)
 // - only touch the TOS (and pop it when finished)
 #define SWAPPABLE(opcode) \
-    ((opcode) == STORE_FAST || (opcode) == POP_TOP)
+    ((opcode) == STORE_FAST || \
+     (opcode) == STORE_FAST_MAYBE_NULL || \
+     (opcode) == POP_TOP)
 
 static int
 next_swappable_instruction(basicblock *block, int i, int lineno)
@@ -1600,6 +1602,8 @@ scan_block_for_locals(basicblock *b, basicblock ***sp)
         uint64_t bit = (uint64_t)1 << instr->i_oparg;
         switch (instr->i_opcode) {
             case DELETE_FAST:
+            case LOAD_FAST_AND_CLEAR:
+            case STORE_FAST_MAYBE_NULL:
                 unsafe_mask |= bit;
                 break;
             case STORE_FAST:
@@ -1639,7 +1643,8 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals)
     Py_ssize_t blocknum = 0;
     // state[i - 64] == blocknum if local i is guaranteed to
     // be initialized, i.e., if it has had a previous LOAD_FAST or
-    // STORE_FAST within that basicblock (not followed by DELETE_FAST).
+    // STORE_FAST within that basicblock (not followed by
+    // DELETE_FAST/LOAD_FAST_AND_CLEAR/STORE_FAST_MAYBE_NULL).
     for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
         blocknum++;
         for (int i = 0; i < b->b_iused; i++) {
@@ -1653,6 +1658,8 @@ fast_scan_many_locals(basicblock *entryblock, int nlocals)
             assert(arg >= 0);
             switch (instr->i_opcode) {
                 case DELETE_FAST:
+                case LOAD_FAST_AND_CLEAR:
+                case STORE_FAST_MAYBE_NULL:
                     states[arg - 64] = blocknum - 1;
                     break;
                 case STORE_FAST:
@@ -1975,7 +1982,7 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
 }
 
 void
-_PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock)
+_PyCfg_ConvertPseudoOps(basicblock *entryblock)
 {
     for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
         for (int i = 0; i < b->b_iused; i++) {
@@ -1983,6 +1990,9 @@ _PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock)
             if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
                 INSTR_SET_OP0(instr, NOP);
             }
+            else if (instr->i_opcode == STORE_FAST_MAYBE_NULL) {
+                instr->i_opcode = STORE_FAST;
+            }
         }
     }
     for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 069a7ced0a4c25..819c857c3c0119 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -92,13 +92,25 @@
             DISPATCH();
         }
 
+        TARGET(LOAD_FAST_AND_CLEAR) {
+            PyObject *value;
+            #line 198 "Python/bytecodes.c"
+            value = GETLOCAL(oparg);
+            // do not use SETLOCAL here, it decrefs the old value
+            GETLOCAL(oparg) = NULL;
+            #line 102 "Python/generated_cases.c.h"
+            STACK_GROW(1);
+            stack_pointer[-1] = value;
+            DISPATCH();
+        }
+
         TARGET(LOAD_CONST) {
             PREDICTED(LOAD_CONST);
             PyObject *value;
-            #line 198 "Python/bytecodes.c"
+            #line 204 "Python/bytecodes.c"
             value = GETITEM(frame->f_code->co_consts, oparg);
             Py_INCREF(value);
-            #line 102 "Python/generated_cases.c.h"
+            #line 114 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -106,9 +118,9 @@
 
         TARGET(STORE_FAST) {
             PyObject *value = stack_pointer[-1];
-            #line 203 "Python/bytecodes.c"
+            #line 209 "Python/bytecodes.c"
             SETLOCAL(oparg, value);
-            #line 112 "Python/generated_cases.c.h"
+            #line 124 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
@@ -122,7 +134,7 @@
                 value = GETLOCAL(oparg);
                 assert(value != NULL);
                 Py_INCREF(value);
-                #line 126 "Python/generated_cases.c.h"
+                #line 138 "Python/generated_cases.c.h"
                 _tmp_2 = value;
             }
             oparg = (next_instr++)->op.arg;
@@ -132,7 +144,7 @@
                 value = GETLOCAL(oparg);
                 assert(value != NULL);
                 Py_INCREF(value);
-                #line 136 "Python/generated_cases.c.h"
+                #line 148 "Python/generated_cases.c.h"
                 _tmp_1 = value;
             }
             STACK_GROW(2);
@@ -150,16 +162,16 @@
                 value = GETLOCAL(oparg);
                 assert(value != NULL);
                 Py_INCREF(value);
-                #line 154 "Python/generated_cases.c.h"
+                #line 166 "Python/generated_cases.c.h"
                 _tmp_2 = value;
             }
             oparg = (next_instr++)->op.arg;
             {
                 PyObject *value;
-                #line 198 "Python/bytecodes.c"
+                #line 204 "Python/bytecodes.c"
                 value = GETITEM(frame->f_code->co_consts, oparg);
                 Py_INCREF(value);
-                #line 163 "Python/generated_cases.c.h"
+                #line 175 "Python/generated_cases.c.h"
                 _tmp_1 = value;
             }
             STACK_GROW(2);
@@ -172,9 +184,9 @@
             PyObject *_tmp_1 = stack_pointer[-1];
             {
                 PyObject *value = _tmp_1;
-                #line 203 "Python/bytecodes.c"
+                #line 209 "Python/bytecodes.c"
                 SETLOCAL(oparg, value);
-                #line 178 "Python/generated_cases.c.h"
+                #line 190 "Python/generated_cases.c.h"
             }
             oparg = (next_instr++)->op.arg;
             {
@@ -183,7 +195,7 @@
                 value = GETLOCAL(oparg);
                 assert(value != NULL);
                 Py_INCREF(value);
-                #line 187 "Python/generated_cases.c.h"
+                #line 199 "Python/generated_cases.c.h"
                 _tmp_1 = value;
             }
             stack_pointer[-1] = _tmp_1;
@@ -195,16 +207,16 @@
             PyObject *_tmp_2 = stack_pointer[-2];
             {
                 PyObject *value = _tmp_1;
-                #line 203 "Python/bytecodes.c"
+                #line 209 "Python/bytecodes.c"
                 SETLOCAL(oparg, value);
-                #line 201 "Python/generated_cases.c.h"
+                #line 213 "Python/generated_cases.c.h"
             }
             oparg = (next_instr++)->op.arg;
             {
                 PyObject *value = _tmp_2;
-                #line 203 "Python/bytecodes.c"
+                #line 209 "Python/bytecodes.c"
                 SETLOCAL(oparg, value);
-                #line 208 "Python/generated_cases.c.h"
+                #line 220 "Python/generated_cases.c.h"
             }
             STACK_SHRINK(2);
             DISPATCH();
@@ -215,10 +227,10 @@
             PyObject *_tmp_2;
             {
                 PyObject *value;
-                #line 198 "Python/bytecodes.c"
+                #line 204 "Python/bytecodes.c"
                 value = GETITEM(frame->f_code->co_consts, oparg);
                 Py_INCREF(value);
-                #line 222 "Python/generated_cases.c.h"
+                #line 234 "Python/generated_cases.c.h"
                 _tmp_2 = value;
             }
             oparg = (next_instr++)->op.arg;
@@ -228,7 +240,7 @@
                 value = GETLOCAL(oparg);
                 assert(value != NULL);
                 Py_INCREF(value);
-                #line 232 "Python/generated_cases.c.h"
+                #line 244 "Python/generated_cases.c.h"
                 _tmp_1 = value;
             }
             STACK_GROW(2);
@@ -239,8 +251,8 @@
 
         TARGET(POP_TOP) {
             PyObject *value = stack_pointer[-1];
-            #line 213 "Python/bytecodes.c"
-            #line 244 "Python/generated_cases.c.h"
+            #line 219 "Python/bytecodes.c"
+            #line 256 "Python/generated_cases.c.h"
             Py_DECREF(value);
             STACK_SHRINK(1);
             DISPATCH();
@@ -248,9 +260,9 @@
 
         TARGET(PUSH_NULL) {
             PyObject *res;
-            #line 217 "Python/bytecodes.c"
+            #line 223 "Python/bytecodes.c"
             res = NULL;
-            #line 254 "Python/generated_cases.c.h"
+            #line 266 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             DISPATCH();
@@ -261,14 +273,14 @@
             PyObject *_tmp_2 = stack_pointer[-2];
             {
                 PyObject *value = _tmp_1;
-                #line 213 "Python/bytecodes.c"
-                #line 266 "Python/generated_cases.c.h"
+                #line 219 "Python/bytecodes.c"
+                #line 278 "Python/generated_cases.c.h"
                 Py_DECREF(value);
             }
             {
                 PyObject *value = _tmp_2;
-                #line 213 "Python/bytecodes.c"
-                #line 272 "Python/generated_cases.c.h"
+                #line 219 "Python/bytecodes.c"
+                #line 284 "Python/generated_cases.c.h"
                 Py_DECREF(value);
             }
             STACK_SHRINK(2);
@@ -278,7 +290,7 @@
         TARGET(INSTRUMENTED_END_FOR) {
             PyObject *value = stack_pointer[-1];
             PyObject *receiver = stack_pointer[-2];
-            #line 223 "Python/bytecodes.c"
+            #line 229 "Python/bytecodes.c"
             /* Need to create a fake StopIteration error here,
              * to conform to PEP 380 */
             if (PyGen_Check(receiver)) {
@@ -288,7 +300,7 @@
                 }
                 PyErr_SetRaisedException(NULL);
             }
-            #line 292 "Python/generated_cases.c.h"
+            #line 304 "Python/generated_cases.c.h"
             Py_DECREF(receiver);
             Py_DECREF(value);
             STACK_SHRINK(2);
@@ -298,9 +310,9 @@
         TARGET(END_SEND) {
             PyObject *value = stack_pointer[-1];
             PyObject *receiver = stack_pointer[-2];
-            #line 236 "Python/bytecodes.c"
+            #line 242 "Python/bytecodes.c"
             Py_DECREF(receiver);
-            #line 304 "Python/generated_cases.c.h"
+            #line 316 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -309,7 +321,7 @@
         TARGET(INSTRUMENTED_END_SEND) {
             PyObject *value = stack_pointer[-1];
             PyObject *receiver = stack_pointer[-2];
-            #line 240 "Python/bytecodes.c"
+            #line 246 "Python/bytecodes.c"
             if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) {
                 PyErr_SetObject(PyExc_StopIteration, value);
                 if (monitor_stop_iteration(tstate, frame, next_instr-1)) {
@@ -318,7 +330,7 @@
                 PyErr_SetRaisedException(NULL);
             }
             Py_DECREF(receiver);
-            #line 322 "Python/generated_cases.c.h"
+            #line 334 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -327,13 +339,13 @@
         TARGET(UNARY_NEGATIVE) {
             PyObject *value = stack_pointer[-1];
             PyObject *res;
-            #line 251 "Python/bytecodes.c"
+            #line 257 "Python/bytecodes.c"
             res = PyNumber_Negative(value);
-            #line 333 "Python/generated_cases.c.h"
+            #line 345 "Python/generated_cases.c.h"
             Py_DECREF(value);
-            #line 253 "Python/bytecodes.c"
+            #line 259 "Python/bytecodes.c"
             if (res == NULL) goto pop_1_error;
-            #line 337 "Python/generated_cases.c.h"
+            #line 349 "Python/generated_cases.c.h"
             stack_pointer[-1] = res;
             DISPATCH();
         }
@@ -341,11 +353,11 @@
         TARGET(UNARY_NOT) {
             PyObject *value = stack_pointer[-1];
             PyObject *res;
-            #line 257 "Python/bytecodes.c"
+            #line 263 "Python/bytecodes.c"
             int err = PyObject_IsTrue(value);
-            #line 347 "Python/generated_cases.c.h"
+            #line 359 "Python/generated_cases.c.h"
             Py_DECREF(value);
-            #line 259 "Python/bytecodes.c"
+            #line 265 "Python/bytecodes.c"
             if (err < 0) goto pop_1_error;
             if (err == 0) {
                 res = Py_True;
@@ -354,7 +366,7 @@
                 res = Py_False;
             }
             Py_INCREF(res);
-            #line 358 "Python/generated_cases.c.h"
+            #line 370 "Python/generated_cases.c.h"
             stack_pointer[-1] = res;
             DISPATCH();
         }
@@ -362,13 +374,13 @@
         TARGET(UNARY_INVERT) {
             PyObject *value = stack_pointer[-1];
             PyObject *res;
-            #line 270 "Python/bytecodes.c"
+            #line 276 "Python/bytecodes.c"
             res = PyNumber_Invert(value);
-            #line 368 "Python/generated_cases.c.h"
+            #line 380 "Python/generated_cases.c.h"
             Py_DECREF(value);
-            #line 272 "Python/bytecodes.c"
+            #line 278 "Python/bytecodes.c"
             if (res == NULL) goto pop_1_error;
-            #line 372 "Python/generated_cases.c.h"
+            #line 384 "Python/generated_cases.c.h"
             stack_pointer[-1] = res;
             DISPATCH();
         }
@@ -377,7 +389,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *prod;
-            #line 289 "Python/bytecodes.c"
+            #line 295 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
             DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
@@ -385,7 +397,7 @@
             _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
             _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
             if (prod == NULL) goto pop_2_error;
-            #line 389 "Python/generated_cases.c.h"
+            #line 401 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = prod;
             next_instr += 1;
@@ -396,14 +408,14 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *prod;
-            #line 299 "Python/bytecodes.c"
+            #line 305 "Python/bytecodes.c"
             DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
             DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
             double dprod = ((PyFloatObject *)left)->ob_fval *
                 ((PyFloatObject *)right)->ob_fval;
             DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod);
-            #line 407 "Python/generated_cases.c.h"
+            #line 419 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = prod;
             next_instr += 1;
@@ -414,7 +426,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *sub;
-            #line 308 "Python/bytecodes.c"
+            #line 314 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
             DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
@@ -422,7 +434,7 @@
             _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
             _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
             if (sub == NULL) goto pop_2_error;
-            #line 426 "Python/generated_cases.c.h"
+            #line 438 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = sub;
             next_instr += 1;
@@ -433,13 +445,13 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *sub;
-            #line 318 "Python/bytecodes.c"
+            #line 324 "Python/bytecodes.c"
             DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
             DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
             double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
             DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub);
-            #line 443 "Python/generated_cases.c.h"
+            #line 455 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = sub;
             next_instr += 1;
@@ -450,7 +462,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *res;
-            #line 326 "Python/bytecodes.c"
+            #line 332 "Python/bytecodes.c"
             DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
             DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
@@ -458,7 +470,7 @@
             _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
             _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
             if (res == NULL) goto pop_2_error;
-            #line 462 "Python/generated_cases.c.h"
+            #line 474 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -468,7 +480,7 @@
         TARGET(BINARY_OP_INPLACE_ADD_UNICODE) {
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
-            #line 342 "Python/bytecodes.c"
+            #line 348 "Python/bytecodes.c"
             DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
             DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
             _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
@@ -495,7 +507,7 @@
             if (*target_local == NULL) goto pop_2_error;
             // The STORE_FAST is already done.
             JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
-            #line 499 "Python/generated_cases.c.h"
+            #line 511 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             DISPATCH();
         }
@@ -504,14 +516,14 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *sum;
-            #line 371 "Python/bytecodes.c"
+            #line 377 "Python/bytecodes.c"
             DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
             DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
             double dsum = ((PyFloatObject *)left)->ob_fval +
                 ((PyFloatObject *)right)->ob_fval;
             DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum);
-            #line 515 "Python/generated_cases.c.h"
+            #line 527 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = sum;
             next_instr += 1;
@@ -522,7 +534,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *sum;
-            #line 380 "Python/bytecodes.c"
+            #line 386 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
             DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
             STAT_INC(BINARY_OP, hit);
@@ -530,7 +542,7 @@
             _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
             _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
             if (sum == NULL) goto pop_2_error;
-            #line 534 "Python/generated_cases.c.h"
+            #line 546 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = sum;
             next_instr += 1;
@@ -543,7 +555,7 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *container = stack_pointer[-2];
             PyObject *res;
-            #line 398 "Python/bytecodes.c"
+            #line 404 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -555,12 +567,12 @@
             DECREMENT_ADAPTIVE_COUNTER(cache->counter);
             #endif  /* ENABLE_SPECIALIZATION */
             res = PyObject_GetItem(container, sub);
-            #line 559 "Python/generated_cases.c.h"
+            #line 571 "Python/generated_cases.c.h"
             Py_DECREF(container);
             Py_DECREF(sub);
-            #line 410 "Python/bytecodes.c"
+            #line 416 "Python/bytecodes.c"
             if (res == NULL) goto pop_2_error;
-            #line 564 "Python/generated_cases.c.h"
+            #line 576 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -572,7 +584,7 @@
             PyObject *start = stack_pointer[-2];
             PyObject *container = stack_pointer[-3];
             PyObject *res;
-            #line 414 "Python/bytecodes.c"
+            #line 420 "Python/bytecodes.c"
             PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
             // Can't use ERROR_IF() here, because we haven't
             // DECREF'ed container yet, and we still own slice.
@@ -585,7 +597,7 @@
             }
             Py_DECREF(container);
             if (res == NULL) goto pop_3_error;
-            #line 589 "Python/generated_cases.c.h"
+            #line 601 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             stack_pointer[-1] = res;
             DISPATCH();
@@ -596,7 +608,7 @@
             PyObject *start = stack_pointer[-2];
             PyObject *container = stack_pointer[-3];
             PyObject *v = stack_pointer[-4];
-            #line 429 "Python/bytecodes.c"
+            #line 435 "Python/bytecodes.c"
             PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
             int err;
             if (slice == NULL) {
@@ -609,7 +621,7 @@
             Py_DECREF(v);
             Py_DECREF(container);
             if (err) goto pop_4_error;
-            #line 613 "Python/generated_cases.c.h"
+            #line 625 "Python/generated_cases.c.h"
             STACK_SHRINK(4);
             DISPATCH();
         }
@@ -618,7 +630,7 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *list = stack_pointer[-2];
             PyObject *res;
-            #line 444 "Python/bytecodes.c"
+            #line 450 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
             DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
 
@@ -632,7 +644,7 @@
             Py_INCREF(res);
             _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
             Py_DECREF(list);
-            #line 636 "Python/generated_cases.c.h"
+            #line 648 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -643,7 +655,7 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *tuple = stack_pointer[-2];
             PyObject *res;
-            #line 460 "Python/bytecodes.c"
+            #line 466 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
             DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
 
@@ -657,7 +669,7 @@
             Py_INCREF(res);
             _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
             Py_DECREF(tuple);
-            #line 661 "Python/generated_cases.c.h"
+            #line 673 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -668,7 +680,7 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *dict = stack_pointer[-2];
             PyObject *res;
-            #line 476 "Python/bytecodes.c"
+            #line 482 "Python/bytecodes.c"
             DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR);
             STAT_INC(BINARY_SUBSCR, hit);
             res = PyDict_GetItemWithError(dict, sub);
@@ -676,14 +688,14 @@
                 if (!_PyErr_Occurred(tstate)) {
                     _PyErr_SetKeyError(sub);
                 }
-            #line 680 "Python/generated_cases.c.h"
+            #line 692 "Python/generated_cases.c.h"
                 Py_DECREF(dict);
                 Py_DECREF(sub);
-            #line 484 "Python/bytecodes.c"
+            #line 490 "Python/bytecodes.c"
                 if (true) goto pop_2_error;
             }
             Py_INCREF(res);  // Do this before DECREF'ing dict, sub
-            #line 687 "Python/generated_cases.c.h"
+            #line 699 "Python/generated_cases.c.h"
             Py_DECREF(dict);
             Py_DECREF(sub);
             STACK_SHRINK(1);
@@ -695,7 +707,7 @@
         TARGET(BINARY_SUBSCR_GETITEM) {
             PyObject *sub = stack_pointer[-1];
             PyObject *container = stack_pointer[-2];
-            #line 491 "Python/bytecodes.c"
+            #line 497 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(container);
             DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR);
             PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
@@ -717,15 +729,15 @@
             JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
             frame->return_offset = 0;
             DISPATCH_INLINED(new_frame);
-            #line 721 "Python/generated_cases.c.h"
+            #line 733 "Python/generated_cases.c.h"
         }
 
         TARGET(LIST_APPEND) {
             PyObject *v = stack_pointer[-1];
             PyObject *list = stack_pointer[-(2 + (oparg-1))];
-            #line 515 "Python/bytecodes.c"
+            #line 521 "Python/bytecodes.c"
             if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error;
-            #line 729 "Python/generated_cases.c.h"
+            #line 741 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             PREDICT(JUMP_BACKWARD);
             DISPATCH();
@@ -734,13 +746,13 @@
         TARGET(SET_ADD) {
             PyObject *v = stack_pointer[-1];
             PyObject *set = stack_pointer[-(2 + (oparg-1))];
-            #line 520 "Python/bytecodes.c"
+            #line 526 "Python/bytecodes.c"
             int err = PySet_Add(set, v);
-            #line 740 "Python/generated_cases.c.h"
+            #line 752 "Python/generated_cases.c.h"
             Py_DECREF(v);
-            #line 522 "Python/bytecodes.c"
+            #line 528 "Python/bytecodes.c"
             if (err) goto pop_1_error;
-            #line 744 "Python/generated_cases.c.h"
+            #line 756 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             PREDICT(JUMP_BACKWARD);
             DISPATCH();
@@ -753,7 +765,7 @@
             PyObject *container = stack_pointer[-2];
             PyObject *v = stack_pointer[-3];
             uint16_t counter = read_u16(&next_instr[0].cache);
-            #line 533 "Python/bytecodes.c"
+            #line 539 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
                 next_instr--;
@@ -768,13 +780,13 @@
             #endif  /* ENABLE_SPECIALIZATION */
             /* container[sub] = v */
             int err = PyObject_SetItem(container, sub, v);
-            #line 772 "Python/generated_cases.c.h"
+            #line 784 "Python/generated_cases.c.h"
             Py_DECREF(v);
             Py_DECREF(container);
             Py_DECREF(sub);
-            #line 548 "Python/bytecodes.c"
+            #line 554 "Python/bytecodes.c"
             if (err) goto pop_3_error;
-            #line 778 "Python/generated_cases.c.h"
+            #line 790 "Python/generated_cases.c.h"
             STACK_SHRINK(3);
             next_instr += 1;
             DISPATCH();
@@ -784,7 +796,7 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *list = stack_pointer[-2];
             PyObject *value = stack_pointer[-3];
-            #line 552 "Python/bytecodes.c"
+            #line 558 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR);
             DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
 
@@ -801,7 +813,7 @@
             Py_DECREF(old_value);
             _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
             Py_DECREF(list);
-            #line 805 "Python/generated_cases.c.h"
+            #line 817 "Python/generated_cases.c.h"
             STACK_SHRINK(3);
             next_instr += 1;
             DISPATCH();
@@ -811,13 +823,13 @@
             PyObject *sub = stack_pointer[-1];
             PyObject *dict = stack_pointer[-2];
             PyObject *value = stack_pointer[-3];
-            #line 571 "Python/bytecodes.c"
+            #line 577 "Python/bytecodes.c"
             DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR);
             STAT_INC(STORE_SUBSCR, hit);
             int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value);
             Py_DECREF(dict);
             if (err) goto pop_3_error;
-            #line 821 "Python/generated_cases.c.h"
+            #line 833 "Python/generated_cases.c.h"
             STACK_SHRINK(3);
             next_instr += 1;
             DISPATCH();
@@ -826,15 +838,15 @@
         TARGET(DELETE_SUBSCR) {
             PyObject *sub = stack_pointer[-1];
             PyObject *container = stack_pointer[-2];
-            #line 579 "Python/bytecodes.c"
+            #line 585 "Python/bytecodes.c"
             /* del container[sub] */
             int err = PyObject_DelItem(container, sub);
-            #line 833 "Python/generated_cases.c.h"
+            #line 845 "Python/generated_cases.c.h"
             Py_DECREF(container);
             Py_DECREF(sub);
-            #line 582 "Python/bytecodes.c"
+            #line 588 "Python/bytecodes.c"
             if (err) goto pop_2_error;
-            #line 838 "Python/generated_cases.c.h"
+            #line 850 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             DISPATCH();
         }
@@ -842,14 +854,14 @@
         TARGET(CALL_INTRINSIC_1) {
             PyObject *value = stack_pointer[-1];
             PyObject *res;
-            #line 586 "Python/bytecodes.c"
+            #line 592 "Python/bytecodes.c"
             assert(oparg <= MAX_INTRINSIC_1);
             res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value);
-            #line 849 "Python/generated_cases.c.h"
+            #line 861 "Python/generated_cases.c.h"
             Py_DECREF(value);
-            #line 589 "Python/bytecodes.c"
+            #line 595 "Python/bytecodes.c"
             if (res == NULL) goto pop_1_error;
-            #line 853 "Python/generated_cases.c.h"
+            #line 865 "Python/generated_cases.c.h"
             stack_pointer[-1] = res;
             DISPATCH();
         }
@@ -858,15 +870,15 @@
             PyObject *value1 = stack_pointer[-1];
             PyObject *value2 = stack_pointer[-2];
             PyObject *res;
-            #line 593 "Python/bytecodes.c"
+            #line 599 "Python/bytecodes.c"
             assert(oparg <= MAX_INTRINSIC_2);
             res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1);
-            #line 865 "Python/generated_cases.c.h"
+            #line 877 "Python/generated_cases.c.h"
             Py_DECREF(value2);
             Py_DECREF(value1);
-            #line 596 "Python/bytecodes.c"
+            #line 602 "Python/bytecodes.c"
             if (res == NULL) goto pop_2_error;
-            #line 870 "Python/generated_cases.c.h"
+            #line 882 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             DISPATCH();
@@ -874,7 +886,7 @@
 
         TARGET(RAISE_VARARGS) {
             PyObject **args = (stack_pointer - oparg);
-            #line 600 "Python/bytecodes.c"
+            #line 606 "Python/bytecodes.c"
             PyObject *cause = NULL, *exc = NULL;
             switch (oparg) {
             case 2:
@@ -892,12 +904,12 @@
                 break;
             }
             if (true) { STACK_SHRINK(oparg); goto error; }
-            #line 896 "Python/generated_cases.c.h"
+            #line 908 "Python/generated_cases.c.h"
         }
 
         TARGET(INTERPRETER_EXIT) {
             PyObject *retval = stack_pointer[-1];
-            #line 620 "Python/bytecodes.c"
+            #line 626 "Python/bytecodes.c"
             assert(frame == &entry_frame);
             assert(_PyFrame_IsIncomplete(frame));
             STACK_SHRINK(1);  // Since we're not going to DISPATCH()
@@ -908,12 +920,12 @@
             assert(!_PyErr_Occurred(tstate));
             _Py_LeaveRecursiveCallTstate(tstate);
             return retval;
-            #line 912 "Python/generated_cases.c.h"
+            #line 924 "Python/generated_cases.c.h"
         }
 
         TARGET(RETURN_VALUE) {
             PyObject *retval = stack_pointer[-1];
-            #line 633 "Python/bytecodes.c"
+            #line 639 "Python/bytecodes.c"
             STACK_SHRINK(1);
             assert(EMPTY());
             _PyFrame_SetStackPointer(frame, stack_pointer);
@@ -926,12 +938,12 @@
             frame->prev_instr += frame->return_offset;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 930 "Python/generated_cases.c.h"
+            #line 942 "Python/generated_cases.c.h"
         }
 
         TARGET(INSTRUMENTED_RETURN_VALUE) {
             PyObject *retval = stack_pointer[-1];
-            #line 648 "Python/bytecodes.c"
+            #line 654 "Python/bytecodes.c"
             int err = _Py_call_instrumentation_arg(
                     tstate, PY_MONITORING_EVENT_PY_RETURN,
                     frame, next_instr-1, retval);
@@ -948,11 +960,11 @@
             frame->prev_instr += frame->return_offset;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 952 "Python/generated_cases.c.h"
+            #line 964 "Python/generated_cases.c.h"
         }
 
         TARGET(RETURN_CONST) {
-            #line 667 "Python/bytecodes.c"
+            #line 673 "Python/bytecodes.c"
             PyObject *retval = GETITEM(frame->f_code->co_consts, oparg);
             Py_INCREF(retval);
             assert(EMPTY());
@@ -966,11 +978,11 @@
             frame->prev_instr += frame->return_offset;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 970 "Python/generated_cases.c.h"
+            #line 982 "Python/generated_cases.c.h"
         }
 
         TARGET(INSTRUMENTED_RETURN_CONST) {
-            #line 683 "Python/bytecodes.c"
+            #line 689 "Python/bytecodes.c"
             PyObject *retval = GETITEM(frame->f_code->co_consts, oparg);
             int err = _Py_call_instrumentation_arg(
                     tstate, PY_MONITORING_EVENT_PY_RETURN,
@@ -988,13 +1000,13 @@
             frame->prev_instr += frame->return_offset;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 992 "Python/generated_cases.c.h"
+            #line 1004 "Python/generated_cases.c.h"
         }
 
         TARGET(GET_AITER) {
             PyObject *obj = stack_pointer[-1];
             PyObject *iter;
-            #line 703 "Python/bytecodes.c"
+            #line 709 "Python/bytecodes.c"
             unaryfunc getter = NULL;
             PyTypeObject *type = Py_TYPE(obj);
 
@@ -1007,16 +1019,16 @@
                               "'async for' requires an object with "
                               "__aiter__ method, got %.100s",
                               type->tp_name);
-            #line 1011 "Python/generated_cases.c.h"
+            #line 1023 "Python/generated_cases.c.h"
                 Py_DECREF(obj);
-            #line 716 "Python/bytecodes.c"
+            #line 722 "Python/bytecodes.c"
                 if (true) goto pop_1_error;
             }
 
             iter = (*getter)(obj);
-            #line 1018 "Python/generated_cases.c.h"
+            #line 1030 "Python/generated_cases.c.h"
             Py_DECREF(obj);
-            #line 721 "Python/bytecodes.c"
+            #line 727 "Python/bytecodes.c"
             if (iter == NULL) goto pop_1_error;
 
             if (Py_TYPE(iter)->tp_as_async == NULL ||
@@ -1029,7 +1041,7 @@
                 Py_DECREF(iter);
                 if (true) goto pop_1_error;
             }
-            #line 1033 "Python/generated_cases.c.h"
+            #line 1045 "Python/generated_cases.c.h"
             stack_pointer[-1] = iter;
             DISPATCH();
         }
@@ -1037,7 +1049,7 @@
         TARGET(GET_ANEXT) {
             PyObject *aiter = stack_pointer[-1];
             PyObject *awaitable;
-            #line 736 "Python/bytecodes.c"
+            #line 742 "Python/bytecodes.c"
             unaryfunc getter = NULL;
             PyObject *next_iter = NULL;
             PyTypeObject *type = Py_TYPE(aiter);
@@ -1081,7 +1093,7 @@
                 }
             }
 
-            #line 1085 "Python/generated_cases.c.h"
+            #line 1097 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = awaitable;
             PREDICT(LOAD_CONST);
@@ -1092,16 +1104,16 @@
             PREDICTED(GET_AWAITABLE);
             PyObject *iterable = stack_pointer[-1];
             PyObject *iter;
-            #line 783 "Python/bytecodes.c"
+            #line 789 "Python/bytecodes.c"
             iter = _PyCoro_GetAwaitableIter(iterable);
 
             if (iter == NULL) {
                 format_awaitable_error(tstate, Py_TYPE(iterable), oparg);
             }
 
-            #line 1103 "Python/generated_cases.c.h"
+            #line 1115 "Python/generated_cases.c.h"
             Py_DECREF(iterable);
-            #line 790 "Python/bytecodes.c"
+            #line 796 "Python/bytecodes.c"
 
             if (iter != NULL && PyCoro_CheckExact(iter)) {
                 PyObject *yf = _PyGen_yf((PyGenObject*)iter);
@@ -1119,7 +1131,7 @@
 
             if (iter == NULL) goto pop_1_error;
 
-            #line 1123 "Python/generated_cases.c.h"
+            #line 1135 "Python/generated_cases.c.h"
             stack_pointer[-1] = iter;
             PREDICT(LOAD_CONST);
             DISPATCH();
@@ -1130,7 +1142,7 @@
             PyObject *v = stack_pointer[-1];
             PyObject *receiver = stack_pointer[-2];
             PyObject *retval;
-            #line 816 "Python/bytecodes.c"
+            #line 822 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PySendCache *cache = (_PySendCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1176,7 +1188,7 @@
                 }
             }
             Py_DECREF(v);
-            #line 1180 "Python/generated_cases.c.h"
+            #line 1192 "Python/generated_cases.c.h"
             stack_pointer[-1] = retval;
             next_instr += 1;
             DISPATCH();
@@ -1185,7 +1197,7 @@
         TARGET(SEND_GEN) {
             PyObject *v = stack_pointer[-1];
             PyObject *receiver = stack_pointer[-2];
-            #line 864 "Python/bytecodes.c"
+            #line 870 "Python/bytecodes.c"
             PyGenObject *gen = (PyGenObject *)receiver;
             DEOPT_IF(Py_TYPE(gen) != &PyGen_Type &&
                      Py_TYPE(gen) != &PyCoro_Type, SEND);
@@ -1200,12 +1212,12 @@
             tstate->exc_info = &gen->gi_exc_state;
             JUMPBY(INLINE_CACHE_ENTRIES_SEND);
             DISPATCH_INLINED(gen_frame);
-            #line 1204 "Python/generated_cases.c.h"
+            #line 1216 "Python/generated_cases.c.h"
         }
 
         TARGET(INSTRUMENTED_YIELD_VALUE) {
             PyObject *retval = stack_pointer[-1];
-            #line 881 "Python/bytecodes.c"
+            #line 887 "Python/bytecodes.c"
             assert(frame != &entry_frame);
             PyGenObject *gen = _PyFrame_GetGenerator(frame);
             gen->gi_frame_state = FRAME_SUSPENDED;
@@ -1222,12 +1234,12 @@
             gen_frame->previous = NULL;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 1226 "Python/generated_cases.c.h"
+            #line 1238 "Python/generated_cases.c.h"
         }
 
         TARGET(YIELD_VALUE) {
             PyObject *retval = stack_pointer[-1];
-            #line 900 "Python/bytecodes.c"
+            #line 906 "Python/bytecodes.c"
             // 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.
@@ -1243,15 +1255,15 @@
             gen_frame->previous = NULL;
             _PyFrame_StackPush(frame, retval);
             goto resume_frame;
-            #line 1247 "Python/generated_cases.c.h"
+            #line 1259 "Python/generated_cases.c.h"
         }
 
         TARGET(POP_EXCEPT) {
             PyObject *exc_value = stack_pointer[-1];
-            #line 918 "Python/bytecodes.c"
+            #line 924 "Python/bytecodes.c"
             _PyErr_StackItem *exc_info = tstate->exc_info;
             Py_XSETREF(exc_info->exc_value, exc_value);
-            #line 1255 "Python/generated_cases.c.h"
+            #line 1267 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
@@ -1259,7 +1271,7 @@
         TARGET(RERAISE) {
             PyObject *exc = stack_pointer[-1];
             PyObject **values = (stack_pointer - (1 + oparg));
-            #line 923 "Python/bytecodes.c"
+            #line 929 "Python/bytecodes.c"
             assert(oparg >= 0 && oparg <= 2);
             if (oparg) {
                 PyObject *lasti = values[0];
@@ -1277,26 +1289,26 @@
             Py_INCREF(exc);
             _PyErr_SetRaisedException(tstate, exc);
             goto exception_unwind;
-            #line 1281 "Python/generated_cases.c.h"
+            #line 1293 "Python/generated_cases.c.h"
         }
 
         TARGET(END_ASYNC_FOR) {
             PyObject *exc = stack_pointer[-1];
             PyObject *awaitable = stack_pointer[-2];
-            #line 943 "Python/bytecodes.c"
+            #line 949 "Python/bytecodes.c"
             assert(exc && PyExceptionInstance_Check(exc));
             if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
-            #line 1290 "Python/generated_cases.c.h"
+            #line 1302 "Python/generated_cases.c.h"
                 Py_DECREF(awaitable);
                 Py_DECREF(exc);
-            #line 946 "Python/bytecodes.c"
+            #line 952 "Python/bytecodes.c"
             }
             else {
                 Py_INCREF(exc);
                 _PyErr_SetRaisedException(tstate, exc);
                 goto exception_unwind;
             }
-            #line 1300 "Python/generated_cases.c.h"
+            #line 1312 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             DISPATCH();
         }
@@ -1307,23 +1319,23 @@
             PyObject *sub_iter = stack_pointer[-3];
             PyObject *none;
             PyObject *value;
-            #line 955 "Python/bytecodes.c"
+            #line 961 "Python/bytecodes.c"
             assert(throwflag);
             assert(exc_value && PyExceptionInstance_Check(exc_value));
             if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) {
                 value = Py_NewRef(((PyStopIterationObject *)exc_value)->value);
-            #line 1316 "Python/generated_cases.c.h"
+            #line 1328 "Python/generated_cases.c.h"
                 Py_DECREF(sub_iter);
                 Py_DECREF(last_sent_val);
                 Py_DECREF(exc_value);
-            #line 960 "Python/bytecodes.c"
+            #line 966 "Python/bytecodes.c"
                 none = Py_NewRef(Py_None);
             }
             else {
                 _PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
                 goto exception_unwind;
             }
-            #line 1327 "Python/generated_cases.c.h"
+            #line 1339 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = value;
             stack_pointer[-2] = none;
@@ -1332,9 +1344,9 @@
 
         TARGET(LOAD_ASSERTION_ERROR) {
             PyObject *value;
-            #line 969 "Python/bytecodes.c"
+            #line 975 "Python/bytecodes.c"
             value = Py_NewRef(PyExc_AssertionError);
-            #line 1338 "Python/generated_cases.c.h"
+            #line 1350 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -1342,7 +1354,7 @@
 
         TARGET(LOAD_BUILD_CLASS) {
             PyObject *bc;
-            #line 973 "Python/bytecodes.c"
+            #line 979 "Python/bytecodes.c"
             if (PyDict_CheckExact(BUILTINS())) {
                 bc = _PyDict_GetItemWithError(BUILTINS(),
                                               &_Py_ID(__build_class__));
@@ -1364,7 +1376,7 @@
                     if (true) goto error;
                 }
             }
-            #line 1368 "Python/generated_cases.c.h"
+            #line 1380 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = bc;
             DISPATCH();
@@ -1372,33 +1384,33 @@
 
         TARGET(STORE_NAME) {
             PyObject *v = stack_pointer[-1];
-            #line 997 "Python/bytecodes.c"
+            #line 1003 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             PyObject *ns = LOCALS();
             int err;
             if (ns == NULL) {
                 _PyErr_Format(tstate, PyExc_SystemError,
                               "no locals found when storing %R", name);
-            #line 1383 "Python/generated_cases.c.h"
+            #line 1395 "Python/generated_cases.c.h"
                 Py_DECREF(v);
-            #line 1004 "Python/bytecodes.c"
+            #line 1010 "Python/bytecodes.c"
                 if (true) goto pop_1_error;
             }
             if (PyDict_CheckExact(ns))
                 err = PyDict_SetItem(ns, name, v);
             else
                 err = PyObject_SetItem(ns, name, v);
-            #line 1392 "Python/generated_cases.c.h"
+            #line 1404 "Python/generated_cases.c.h"
             Py_DECREF(v);
-            #line 1011 "Python/bytecodes.c"
+            #line 1017 "Python/bytecodes.c"
             if (err) goto pop_1_error;
-            #line 1396 "Python/generated_cases.c.h"
+            #line 1408 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(DELETE_NAME) {
-            #line 1015 "Python/bytecodes.c"
+            #line 1021 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             PyObject *ns = LOCALS();
             int err;
@@ -1415,7 +1427,7 @@
                                      name);
                 goto error;
             }
-            #line 1419 "Python/generated_cases.c.h"
+            #line 1431 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
@@ -1423,7 +1435,7 @@
             PREDICTED(UNPACK_SEQUENCE);
             static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size");
             PyObject *seq = stack_pointer[-1];
-            #line 1041 "Python/bytecodes.c"
+            #line 1047 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1436,11 +1448,11 @@
             #endif  /* ENABLE_SPECIALIZATION */
             PyObject **top = stack_pointer + oparg - 1;
             int res = unpack_iterable(tstate, seq, oparg, -1, top);
-            #line 1440 "Python/generated_cases.c.h"
+            #line 1452 "Python/generated_cases.c.h"
             Py_DECREF(seq);
-            #line 1054 "Python/bytecodes.c"
+            #line 1060 "Python/bytecodes.c"
             if (res == 0) goto pop_1_error;
-            #line 1444 "Python/generated_cases.c.h"
+            #line 1456 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             STACK_GROW(oparg);
             next_instr += 1;
@@ -1450,14 +1462,14 @@
         TARGET(UNPACK_SEQUENCE_TWO_TUPLE) {
             PyObject *seq = stack_pointer[-1];
             PyObject **values = stack_pointer - (1);
-            #line 1058 "Python/bytecodes.c"
+            #line 1064 "Python/bytecodes.c"
             DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
             DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE);
             assert(oparg == 2);
             STAT_INC(UNPACK_SEQUENCE, hit);
             values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1));
             values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0));
-            #line 1461 "Python/generated_cases.c.h"
+            #line 1473 "Python/generated_cases.c.h"
             Py_DECREF(seq);
             STACK_SHRINK(1);
             STACK_GROW(oparg);
@@ -1468,7 +1480,7 @@
         TARGET(UNPACK_SEQUENCE_TUPLE) {
             PyObject *seq = stack_pointer[-1];
             PyObject **values = stack_pointer - (1);
-            #line 1068 "Python/bytecodes.c"
+            #line 1074 "Python/bytecodes.c"
             DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
             DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
             STAT_INC(UNPACK_SEQUENCE, hit);
@@ -1476,7 +1488,7 @@
             for (int i = oparg; --i >= 0; ) {
                 *values++ = Py_NewRef(items[i]);
             }
-            #line 1480 "Python/generated_cases.c.h"
+            #line 1492 "Python/generated_cases.c.h"
             Py_DECREF(seq);
             STACK_SHRINK(1);
             STACK_GROW(oparg);
@@ -1487,7 +1499,7 @@
         TARGET(UNPACK_SEQUENCE_LIST) {
             PyObject *seq = stack_pointer[-1];
             PyObject **values = stack_pointer - (1);
-            #line 1079 "Python/bytecodes.c"
+            #line 1085 "Python/bytecodes.c"
             DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE);
             DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
             STAT_INC(UNPACK_SEQUENCE, hit);
@@ -1495,7 +1507,7 @@
             for (int i = oparg; --i >= 0; ) {
                 *values++ = Py_NewRef(items[i]);
             }
-            #line 1499 "Python/generated_cases.c.h"
+            #line 1511 "Python/generated_cases.c.h"
             Py_DECREF(seq);
             STACK_SHRINK(1);
             STACK_GROW(oparg);
@@ -1505,15 +1517,15 @@
 
         TARGET(UNPACK_EX) {
             PyObject *seq = stack_pointer[-1];
-            #line 1090 "Python/bytecodes.c"
+            #line 1096 "Python/bytecodes.c"
             int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
             PyObject **top = stack_pointer + totalargs - 1;
             int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top);
-            #line 1513 "Python/generated_cases.c.h"
+            #line 1525 "Python/generated_cases.c.h"
             Py_DECREF(seq);
-            #line 1094 "Python/bytecodes.c"
+            #line 1100 "Python/bytecodes.c"
             if (res == 0) goto pop_1_error;
-            #line 1517 "Python/generated_cases.c.h"
+            #line 1529 "Python/generated_cases.c.h"
             STACK_GROW((oparg & 0xFF) + (oparg >> 8));
             DISPATCH();
         }
@@ -1524,7 +1536,7 @@
             PyObject *owner = stack_pointer[-1];
             PyObject *v = stack_pointer[-2];
             uint16_t counter = read_u16(&next_instr[0].cache);
-            #line 1105 "Python/bytecodes.c"
+            #line 1111 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
                 PyObject *name = GETITEM(frame->f_code->co_names, oparg);
@@ -1540,12 +1552,12 @@
             #endif  /* ENABLE_SPECIALIZATION */
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             int err = PyObject_SetAttr(owner, name, v);
-            #line 1544 "Python/generated_cases.c.h"
+            #line 1556 "Python/generated_cases.c.h"
             Py_DECREF(v);
             Py_DECREF(owner);
-            #line 1121 "Python/bytecodes.c"
+            #line 1127 "Python/bytecodes.c"
             if (err) goto pop_2_error;
-            #line 1549 "Python/generated_cases.c.h"
+            #line 1561 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             next_instr += 4;
             DISPATCH();
@@ -1553,34 +1565,34 @@
 
         TARGET(DELETE_ATTR) {
             PyObject *owner = stack_pointer[-1];
-            #line 1125 "Python/bytecodes.c"
+            #line 1131 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             int err = PyObject_SetAttr(owner, name, (PyObject *)NULL);
-            #line 1560 "Python/generated_cases.c.h"
+            #line 1572 "Python/generated_cases.c.h"
             Py_DECREF(owner);
-            #line 1128 "Python/bytecodes.c"
+            #line 1134 "Python/bytecodes.c"
             if (err) goto pop_1_error;
-            #line 1564 "Python/generated_cases.c.h"
+            #line 1576 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(STORE_GLOBAL) {
             PyObject *v = stack_pointer[-1];
-            #line 1132 "Python/bytecodes.c"
+            #line 1138 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             int err = PyDict_SetItem(GLOBALS(), name, v);
-            #line 1574 "Python/generated_cases.c.h"
+            #line 1586 "Python/generated_cases.c.h"
             Py_DECREF(v);
-            #line 1135 "Python/bytecodes.c"
+            #line 1141 "Python/bytecodes.c"
             if (err) goto pop_1_error;
-            #line 1578 "Python/generated_cases.c.h"
+            #line 1590 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(DELETE_GLOBAL) {
-            #line 1139 "Python/bytecodes.c"
+            #line 1145 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             int err;
             err = PyDict_DelItem(GLOBALS(), name);
@@ -1592,13 +1604,13 @@
                 }
                 goto error;
             }
-            #line 1596 "Python/generated_cases.c.h"
+            #line 1608 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(LOAD_NAME) {
             PyObject *v;
-            #line 1153 "Python/bytecodes.c"
+            #line 1159 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             PyObject *locals = LOCALS();
             if (locals == NULL) {
@@ -1657,7 +1669,7 @@
                     }
                 }
             }
-            #line 1661 "Python/generated_cases.c.h"
+            #line 1673 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = v;
             DISPATCH();
@@ -1668,7 +1680,7 @@
             static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
             PyObject *null = NULL;
             PyObject *v;
-            #line 1220 "Python/bytecodes.c"
+            #line 1226 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -1720,7 +1732,7 @@
                 }
             }
             null = NULL;
-            #line 1724 "Python/generated_cases.c.h"
+            #line 1736 "Python/generated_cases.c.h"
             STACK_GROW(1);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = v;
@@ -1734,7 +1746,7 @@
             PyObject *res;
             uint16_t index = read_u16(&next_instr[1].cache);
             uint16_t version = read_u16(&next_instr[2].cache);
-            #line 1274 "Python/bytecodes.c"
+            #line 1280 "Python/bytecodes.c"
             DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
             PyDictObject *dict = (PyDictObject *)GLOBALS();
             DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL);
@@ -1745,7 +1757,7 @@
             Py_INCREF(res);
             STAT_INC(LOAD_GLOBAL, hit);
             null = NULL;
-            #line 1749 "Python/generated_cases.c.h"
+            #line 1761 "Python/generated_cases.c.h"
             STACK_GROW(1);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -1760,7 +1772,7 @@
             uint16_t index = read_u16(&next_instr[1].cache);
             uint16_t mod_version = read_u16(&next_instr[2].cache);
             uint16_t bltn_version = read_u16(&next_instr[3].cache);
-            #line 1287 "Python/bytecodes.c"
+            #line 1293 "Python/bytecodes.c"
             DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
             DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL);
             PyDictObject *mdict = (PyDictObject *)GLOBALS();
@@ -1775,7 +1787,7 @@
             Py_INCREF(res);
             STAT_INC(LOAD_GLOBAL, hit);
             null = NULL;
-            #line 1779 "Python/generated_cases.c.h"
+            #line 1791 "Python/generated_cases.c.h"
             STACK_GROW(1);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -1785,16 +1797,16 @@
         }
 
         TARGET(DELETE_FAST) {
-            #line 1304 "Python/bytecodes.c"
+            #line 1310 "Python/bytecodes.c"
             PyObject *v = GETLOCAL(oparg);
             if (v == NULL) goto unbound_local_error;
             SETLOCAL(oparg, NULL);
-            #line 1793 "Python/generated_cases.c.h"
+            #line 1805 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(MAKE_CELL) {
-            #line 1310 "Python/bytecodes.c"
+            #line 1316 "Python/bytecodes.c"
             // "initial" is probably NULL but not if it's an arg (or set
             // via PyFrame_LocalsToFast() before MAKE_CELL has run).
             PyObject *initial = GETLOCAL(oparg);
@@ -1803,12 +1815,12 @@
                 goto resume_with_error;
             }
             SETLOCAL(oparg, cell);
-            #line 1807 "Python/generated_cases.c.h"
+            #line 1819 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(DELETE_DEREF) {
-            #line 1321 "Python/bytecodes.c"
+            #line 1327 "Python/bytecodes.c"
             PyObject *cell = GETLOCAL(oparg);
             PyObject *oldobj = PyCell_GET(cell);
             // Can't use ERROR_IF here.
@@ -1819,13 +1831,13 @@
             }
             PyCell_SET(cell, NULL);
             Py_DECREF(oldobj);
-            #line 1823 "Python/generated_cases.c.h"
+            #line 1835 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(LOAD_CLASSDEREF) {
             PyObject *value;
-            #line 1334 "Python/bytecodes.c"
+            #line 1340 "Python/bytecodes.c"
             PyObject *name, *locals = LOCALS();
             assert(locals);
             assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus);
@@ -1857,7 +1869,7 @@
                 }
                 Py_INCREF(value);
             }
-            #line 1861 "Python/generated_cases.c.h"
+            #line 1873 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -1865,7 +1877,7 @@
 
         TARGET(LOAD_DEREF) {
             PyObject *value;
-            #line 1368 "Python/bytecodes.c"
+            #line 1374 "Python/bytecodes.c"
             PyObject *cell = GETLOCAL(oparg);
             value = PyCell_GET(cell);
             if (value == NULL) {
@@ -1873,7 +1885,7 @@
                 if (true) goto error;
             }
             Py_INCREF(value);
-            #line 1877 "Python/generated_cases.c.h"
+            #line 1889 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = value;
             DISPATCH();
@@ -1881,18 +1893,18 @@
 
         TARGET(STORE_DEREF) {
             PyObject *v = stack_pointer[-1];
-            #line 1378 "Python/bytecodes.c"
+            #line 1384 "Python/bytecodes.c"
             PyObject *cell = GETLOCAL(oparg);
             PyObject *oldobj = PyCell_GET(cell);
             PyCell_SET(cell, v);
             Py_XDECREF(oldobj);
-            #line 1890 "Python/generated_cases.c.h"
+            #line 1902 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(COPY_FREE_VARS) {
-            #line 1385 "Python/bytecodes.c"
+            #line 1391 "Python/bytecodes.c"
             /* Copy closure variables to free variables */
             PyCodeObject *co = frame->f_code;
             assert(PyFunction_Check(frame->f_funcobj));
@@ -1903,22 +1915,22 @@
                 PyObject *o = PyTuple_GET_ITEM(closure, i);
                 frame->localsplus[offset + i] = Py_NewRef(o);
             }
-            #line 1907 "Python/generated_cases.c.h"
+            #line 1919 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(BUILD_STRING) {
             PyObject **pieces = (stack_pointer - oparg);
             PyObject *str;
-            #line 1398 "Python/bytecodes.c"
+            #line 1404 "Python/bytecodes.c"
             str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg);
-            #line 1916 "Python/generated_cases.c.h"
+            #line 1928 "Python/generated_cases.c.h"
             for (int _i = oparg; --_i >= 0;) {
                 Py_DECREF(pieces[_i]);
             }
-            #line 1400 "Python/bytecodes.c"
+            #line 1406 "Python/bytecodes.c"
             if (str == NULL) { STACK_SHRINK(oparg); goto error; }
-            #line 1922 "Python/generated_cases.c.h"
+            #line 1934 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_GROW(1);
             stack_pointer[-1] = str;
@@ -1928,10 +1940,10 @@
         TARGET(BUILD_TUPLE) {
             PyObject **values = (stack_pointer - oparg);
             PyObject *tup;
-            #line 1404 "Python/bytecodes.c"
+            #line 1410 "Python/bytecodes.c"
             tup = _PyTuple_FromArraySteal(values, oparg);
             if (tup == NULL) { STACK_SHRINK(oparg); goto error; }
-            #line 1935 "Python/generated_cases.c.h"
+            #line 1947 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_GROW(1);
             stack_pointer[-1] = tup;
@@ -1941,10 +1953,10 @@
         TARGET(BUILD_LIST) {
             PyObject **values = (stack_pointer - oparg);
             PyObject *list;
-            #line 1409 "Python/bytecodes.c"
+            #line 1415 "Python/bytecodes.c"
             list = _PyList_FromArraySteal(values, oparg);
             if (list == NULL) { STACK_SHRINK(oparg); goto error; }
-            #line 1948 "Python/generated_cases.c.h"
+            #line 1960 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_GROW(1);
             stack_pointer[-1] = list;
@@ -1954,7 +1966,7 @@
         TARGET(LIST_EXTEND) {
             PyObject *iterable = stack_pointer[-1];
             PyObject *list = stack_pointer[-(2 + (oparg-1))];
-            #line 1414 "Python/bytecodes.c"
+            #line 1420 "Python/bytecodes.c"
             PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
             if (none_val == NULL) {
                 if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) &&
@@ -1965,13 +1977,13 @@
                           "Value after * must be an iterable, not %.200s",
                           Py_TYPE(iterable)->tp_name);
                 }
-            #line 1969 "Python/generated_cases.c.h"
+            #line 1981 "Python/generated_cases.c.h"
                 Py_DECREF(iterable);
-            #line 1425 "Python/bytecodes.c"
+            #line 1431 "Python/bytecodes.c"
                 if (true) goto pop_1_error;
             }
             Py_DECREF(none_val);
-            #line 1975 "Python/generated_cases.c.h"
+            #line 1987 "Python/generated_cases.c.h"
             Py_DECREF(iterable);
             STACK_SHRINK(1);
             DISPATCH();
@@ -1980,13 +1992,13 @@
         TARGET(SET_UPDATE) {
             PyObject *iterable = stack_pointer[-1];
             PyObject *set = stack_pointer[-(2 + (oparg-1))];
-            #line 1432 "Python/bytecodes.c"
+            #line 1438 "Python/bytecodes.c"
             int err = _PySet_Update(set, iterable);
-            #line 1986 "Python/generated_cases.c.h"
+            #line 1998 "Python/generated_cases.c.h"
             Py_DECREF(iterable);
-            #line 1434 "Python/bytecodes.c"
+            #line 1440 "Python/bytecodes.c"
             if (err < 0) goto pop_1_error;
-            #line 1990 "Python/generated_cases.c.h"
+            #line 2002 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
@@ -1994,7 +2006,7 @@
         TARGET(BUILD_SET) {
             PyObject **values = (stack_pointer - oparg);
             PyObject *set;
-            #line 1438 "Python/bytecodes.c"
+            #line 1444 "Python/bytecodes.c"
             set = PySet_New(NULL);
             if (set == NULL)
                 goto error;
@@ -2009,7 +2021,7 @@
                 Py_DECREF(set);
                 if (true) { STACK_SHRINK(oparg); goto error; }
             }
-            #line 2013 "Python/generated_cases.c.h"
+            #line 2025 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_GROW(1);
             stack_pointer[-1] = set;
@@ -2019,7 +2031,7 @@
         TARGET(BUILD_MAP) {
             PyObject **values = (stack_pointer - oparg*2);
             PyObject *map;
-            #line 1455 "Python/bytecodes.c"
+            #line 1461 "Python/bytecodes.c"
             map = _PyDict_FromItems(
                     values, 2,
                     values+1, 2,
@@ -2027,13 +2039,13 @@
             if (map == NULL)
                 goto error;
 
-            #line 2031 "Python/generated_cases.c.h"
+            #line 2043 "Python/generated_cases.c.h"
             for (int _i = oparg*2; --_i >= 0;) {
                 Py_DECREF(values[_i]);
             }
-            #line 1463 "Python/bytecodes.c"
+            #line 1469 "Python/bytecodes.c"
             if (map == NULL) { STACK_SHRINK(oparg*2); goto error; }
-            #line 2037 "Python/generated_cases.c.h"
+            #line 2049 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg*2);
             STACK_GROW(1);
             stack_pointer[-1] = map;
@@ -2041,7 +2053,7 @@
         }
 
         TARGET(SETUP_ANNOTATIONS) {
-            #line 1467 "Python/bytecodes.c"
+            #line 1473 "Python/bytecodes.c"
             int err;
             PyObject *ann_dict;
             if (LOCALS() == NULL) {
@@ -2081,7 +2093,7 @@
                     Py_DECREF(ann_dict);
                 }
             }
-            #line 2085 "Python/generated_cases.c.h"
+            #line 2097 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
@@ -2089,7 +2101,7 @@
             PyObject *keys = stack_pointer[-1];
             PyObject **values = (stack_pointer - (1 + oparg));
             PyObject *map;
-            #line 1509 "Python/bytecodes.c"
+            #line 1515 "Python/bytecodes.c"
             if (!PyTuple_CheckExact(keys) ||
                 PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
                 _PyErr_SetString(tstate, PyExc_SystemError,
@@ -2099,14 +2111,14 @@
             map = _PyDict_FromItems(
                     &PyTuple_GET_ITEM(keys, 0), 1,
                     values, 1, oparg);
-            #line 2103 "Python/generated_cases.c.h"
+            #line 2115 "Python/generated_cases.c.h"
             for (int _i = oparg; --_i >= 0;) {
                 Py_DECREF(values[_i]);
             }
             Py_DECREF(keys);
-            #line 1519 "Python/bytecodes.c"
+            #line 1525 "Python/bytecodes.c"
             if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; }
-            #line 2110 "Python/generated_cases.c.h"
+            #line 2122 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             stack_pointer[-1] = map;
             DISPATCH();
@@ -2114,7 +2126,7 @@
 
         TARGET(DICT_UPDATE) {
             PyObject *update = stack_pointer[-1];
-            #line 1523 "Python/bytecodes.c"
+            #line 1529 "Python/bytecodes.c"
             PyObject *dict = PEEK(oparg + 1);  // update is still on the stack
             if (PyDict_Update(dict, update) < 0) {
                 if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
@@ -2122,12 +2134,12 @@
                                     "'%.200s' object is not a mapping",
                                     Py_TYPE(update)->tp_name);
                 }
-            #line 2126 "Python/generated_cases.c.h"
+            #line 2138 "Python/generated_cases.c.h"
                 Py_DECREF(update);
-            #line 1531 "Python/bytecodes.c"
+            #line 1537 "Python/bytecodes.c"
                 if (true) goto pop_1_error;
             }
-            #line 2131 "Python/generated_cases.c.h"
+            #line 2143 "Python/generated_cases.c.h"
             Py_DECREF(update);
             STACK_SHRINK(1);
             DISPATCH();
@@ -2135,17 +2147,17 @@
 
         TARGET(DICT_MERGE) {
             PyObject *update = stack_pointer[-1];
-            #line 1537 "Python/bytecodes.c"
+            #line 1543 "Python/bytecodes.c"
             PyObject *dict = PEEK(oparg + 1);  // update is still on the stack
 
             if (_PyDict_MergeEx(dict, update, 2) < 0) {
                 format_kwargs_error(tstate, PEEK(3 + oparg), update);
-            #line 2144 "Python/generated_cases.c.h"
+            #line 2156 "Python/generated_cases.c.h"
                 Py_DECREF(update);
-            #line 1542 "Python/bytecodes.c"
+            #line 1548 "Python/bytecodes.c"
                 if (true) goto pop_1_error;
             }
-            #line 2149 "Python/generated_cases.c.h"
+            #line 2161 "Python/generated_cases.c.h"
             Py_DECREF(update);
             STACK_SHRINK(1);
             PREDICT(CALL_FUNCTION_EX);
@@ -2155,13 +2167,13 @@
         TARGET(MAP_ADD) {
             PyObject *value = stack_pointer[-1];
             PyObject *key = stack_pointer[-2];
-            #line 1549 "Python/bytecodes.c"
+            #line 1555 "Python/bytecodes.c"
             PyObject *dict = PEEK(oparg + 2);  // key, value are still on the stack
             assert(PyDict_CheckExact(dict));
             /* dict[key] = value */
             // Do not DECREF INPUTS because the function steals the references
             if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error;
-            #line 2165 "Python/generated_cases.c.h"
+            #line 2177 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             PREDICT(JUMP_BACKWARD);
             DISPATCH();
@@ -2175,7 +2187,7 @@
             PyObject *global_super = stack_pointer[-3];
             PyObject *res2 = NULL;
             PyObject *res;
-            #line 1563 "Python/bytecodes.c"
+            #line 1569 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2);
             int load_method = oparg & 1;
             #if ENABLE_SPECIALIZATION
@@ -2193,16 +2205,16 @@
             // handle any case whose performance we care about
             PyObject *stack[] = {class, self};
             PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
-            #line 2197 "Python/generated_cases.c.h"
+            #line 2209 "Python/generated_cases.c.h"
             Py_DECREF(global_super);
             Py_DECREF(class);
             Py_DECREF(self);
-            #line 1581 "Python/bytecodes.c"
+            #line 1587 "Python/bytecodes.c"
             if (super == NULL) goto pop_3_error;
             res = PyObject_GetAttr(super, name);
             Py_DECREF(super);
             if (res == NULL) goto pop_3_error;
-            #line 2206 "Python/generated_cases.c.h"
+            #line 2218 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2220,7 +2232,7 @@
             uint32_t class_version = read_u32(&next_instr[1].cache);
             uint32_t self_type_version = read_u32(&next_instr[3].cache);
             PyObject *method = read_obj(&next_instr[5].cache);
-            #line 1588 "Python/bytecodes.c"
+            #line 1594 "Python/bytecodes.c"
             DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
             DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
             DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR);
@@ -2231,7 +2243,7 @@
             Py_INCREF(res2);
             Py_DECREF(global_super);
             Py_DECREF(class);
-            #line 2235 "Python/generated_cases.c.h"
+            #line 2247 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             stack_pointer[-2] = res2;
@@ -2245,7 +2257,7 @@
             PyObject *owner = stack_pointer[-1];
             PyObject *res2 = NULL;
             PyObject *res;
-            #line 1615 "Python/bytecodes.c"
+            #line 1621 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyAttrCache *cache = (_PyAttrCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -2279,9 +2291,9 @@
 
                        NULL | meth | arg1 | ... | argN
                     */
-            #line 2283 "Python/generated_cases.c.h"
+            #line 2295 "Python/generated_cases.c.h"
                     Py_DECREF(owner);
-            #line 1649 "Python/bytecodes.c"
+            #line 1655 "Python/bytecodes.c"
                     if (meth == NULL) goto pop_1_error;
                     res2 = NULL;
                     res = meth;
@@ -2290,12 +2302,12 @@
             else {
                 /* Classic, pushes one value. */
                 res = PyObject_GetAttr(owner, name);
-            #line 2294 "Python/generated_cases.c.h"
+            #line 2306 "Python/generated_cases.c.h"
                 Py_DECREF(owner);
-            #line 1658 "Python/bytecodes.c"
+            #line 1664 "Python/bytecodes.c"
                 if (res == NULL) goto pop_1_error;
             }
-            #line 2299 "Python/generated_cases.c.h"
+            #line 2311 "Python/generated_cases.c.h"
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
             if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -2309,7 +2321,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1663 "Python/bytecodes.c"
+            #line 1669 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2322,7 +2334,7 @@
             STAT_INC(LOAD_ATTR, hit);
             Py_INCREF(res);
             res2 = NULL;
-            #line 2326 "Python/generated_cases.c.h"
+            #line 2338 "Python/generated_cases.c.h"
             Py_DECREF(owner);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2337,7 +2349,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1679 "Python/bytecodes.c"
+            #line 1685 "Python/bytecodes.c"
             DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR);
             PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict;
             assert(dict != NULL);
@@ -2350,7 +2362,7 @@
             STAT_INC(LOAD_ATTR, hit);
             Py_INCREF(res);
             res2 = NULL;
-            #line 2354 "Python/generated_cases.c.h"
+            #line 2366 "Python/generated_cases.c.h"
             Py_DECREF(owner);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2365,7 +2377,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1695 "Python/bytecodes.c"
+            #line 1701 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2392,7 +2404,7 @@
             STAT_INC(LOAD_ATTR, hit);
             Py_INCREF(res);
             res2 = NULL;
-            #line 2396 "Python/generated_cases.c.h"
+            #line 2408 "Python/generated_cases.c.h"
             Py_DECREF(owner);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2407,7 +2419,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1725 "Python/bytecodes.c"
+            #line 1731 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2417,7 +2429,7 @@
             STAT_INC(LOAD_ATTR, hit);
             Py_INCREF(res);
             res2 = NULL;
-            #line 2421 "Python/generated_cases.c.h"
+            #line 2433 "Python/generated_cases.c.h"
             Py_DECREF(owner);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2432,7 +2444,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             PyObject *descr = read_obj(&next_instr[5].cache);
-            #line 1738 "Python/bytecodes.c"
+            #line 1744 "Python/bytecodes.c"
 
             DEOPT_IF(!PyType_Check(cls), LOAD_ATTR);
             DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
@@ -2444,7 +2456,7 @@
             res = descr;
             assert(res != NULL);
             Py_INCREF(res);
-            #line 2448 "Python/generated_cases.c.h"
+            #line 2460 "Python/generated_cases.c.h"
             Py_DECREF(cls);
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
@@ -2458,7 +2470,7 @@
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint32_t func_version = read_u32(&next_instr[3].cache);
             PyObject *fget = read_obj(&next_instr[5].cache);
-            #line 1753 "Python/bytecodes.c"
+            #line 1759 "Python/bytecodes.c"
             DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
 
             PyTypeObject *cls = Py_TYPE(owner);
@@ -2482,7 +2494,7 @@
             JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
             frame->return_offset = 0;
             DISPATCH_INLINED(new_frame);
-            #line 2486 "Python/generated_cases.c.h"
+            #line 2498 "Python/generated_cases.c.h"
         }
 
         TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) {
@@ -2490,7 +2502,7 @@
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint32_t func_version = read_u32(&next_instr[3].cache);
             PyObject *getattribute = read_obj(&next_instr[5].cache);
-            #line 1779 "Python/bytecodes.c"
+            #line 1785 "Python/bytecodes.c"
             DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
             PyTypeObject *cls = Py_TYPE(owner);
             DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -2516,7 +2528,7 @@
             JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
             frame->return_offset = 0;
             DISPATCH_INLINED(new_frame);
-            #line 2520 "Python/generated_cases.c.h"
+            #line 2532 "Python/generated_cases.c.h"
         }
 
         TARGET(STORE_ATTR_INSTANCE_VALUE) {
@@ -2524,7 +2536,7 @@
             PyObject *value = stack_pointer[-2];
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1807 "Python/bytecodes.c"
+            #line 1813 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2542,7 +2554,7 @@
                 Py_DECREF(old_value);
             }
             Py_DECREF(owner);
-            #line 2546 "Python/generated_cases.c.h"
+            #line 2558 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             next_instr += 4;
             DISPATCH();
@@ -2553,7 +2565,7 @@
             PyObject *value = stack_pointer[-2];
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t hint = read_u16(&next_instr[3].cache);
-            #line 1827 "Python/bytecodes.c"
+            #line 1833 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2592,7 +2604,7 @@
             /* PEP 509 */
             dict->ma_version_tag = new_version;
             Py_DECREF(owner);
-            #line 2596 "Python/generated_cases.c.h"
+            #line 2608 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             next_instr += 4;
             DISPATCH();
@@ -2603,7 +2615,7 @@
             PyObject *value = stack_pointer[-2];
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint16_t index = read_u16(&next_instr[3].cache);
-            #line 1868 "Python/bytecodes.c"
+            #line 1874 "Python/bytecodes.c"
             PyTypeObject *tp = Py_TYPE(owner);
             assert(type_version != 0);
             DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2613,7 +2625,7 @@
             *(PyObject **)addr = value;
             Py_XDECREF(old_value);
             Py_DECREF(owner);
-            #line 2617 "Python/generated_cases.c.h"
+            #line 2629 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             next_instr += 4;
             DISPATCH();
@@ -2625,7 +2637,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *res;
-            #line 1887 "Python/bytecodes.c"
+            #line 1893 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -2638,12 +2650,12 @@
             #endif  /* ENABLE_SPECIALIZATION */
             assert((oparg >> 4) <= Py_GE);
             res = PyObject_RichCompare(left, right, oparg>>4);
-            #line 2642 "Python/generated_cases.c.h"
+            #line 2654 "Python/generated_cases.c.h"
             Py_DECREF(left);
             Py_DECREF(right);
-            #line 1900 "Python/bytecodes.c"
+            #line 1906 "Python/bytecodes.c"
             if (res == NULL) goto pop_2_error;
-            #line 2647 "Python/generated_cases.c.h"
+            #line 2659 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -2654,7 +2666,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *res;
-            #line 1904 "Python/bytecodes.c"
+            #line 1910 "Python/bytecodes.c"
             DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
             DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
             STAT_INC(COMPARE_OP, hit);
@@ -2666,7 +2678,7 @@
             _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
             res = (sign_ish & oparg) ? Py_True : Py_False;
             Py_INCREF(res);
-            #line 2670 "Python/generated_cases.c.h"
+            #line 2682 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -2677,7 +2689,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *res;
-            #line 1919 "Python/bytecodes.c"
+            #line 1925 "Python/bytecodes.c"
             DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
             DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
             DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP);
@@ -2693,7 +2705,7 @@
             _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
             res = (sign_ish & oparg) ? Py_True : Py_False;
             Py_INCREF(res);
-            #line 2697 "Python/generated_cases.c.h"
+            #line 2709 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -2704,7 +2716,7 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *res;
-            #line 1938 "Python/bytecodes.c"
+            #line 1944 "Python/bytecodes.c"
             DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
             DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
             STAT_INC(COMPARE_OP, hit);
@@ -2717,7 +2729,7 @@
             assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
             res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False;
             Py_INCREF(res);
-            #line 2721 "Python/generated_cases.c.h"
+            #line 2733 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -2728,14 +2740,14 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *b;
-            #line 1953 "Python/bytecodes.c"
+            #line 1959 "Python/bytecodes.c"
             int res = Py_Is(left, right) ^ oparg;
-            #line 2734 "Python/generated_cases.c.h"
+            #line 2746 "Python/generated_cases.c.h"
             Py_DECREF(left);
             Py_DECREF(right);
-            #line 1955 "Python/bytecodes.c"
+            #line 1961 "Python/bytecodes.c"
             b = Py_NewRef(res ? Py_True : Py_False);
-            #line 2739 "Python/generated_cases.c.h"
+            #line 2751 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = b;
             DISPATCH();
@@ -2745,15 +2757,15 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *b;
-            #line 1959 "Python/bytecodes.c"
+            #line 1965 "Python/bytecodes.c"
             int res = PySequence_Contains(right, left);
-            #line 2751 "Python/generated_cases.c.h"
+            #line 2763 "Python/generated_cases.c.h"
             Py_DECREF(left);
             Py_DECREF(right);
-            #line 1961 "Python/bytecodes.c"
+            #line 1967 "Python/bytecodes.c"
             if (res < 0) goto pop_2_error;
             b = Py_NewRef((res^oparg) ? Py_True : Py_False);
-            #line 2757 "Python/generated_cases.c.h"
+            #line 2769 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = b;
             DISPATCH();
@@ -2764,12 +2776,12 @@
             PyObject *exc_value = stack_pointer[-2];
             PyObject *rest;
             PyObject *match;
-            #line 1966 "Python/bytecodes.c"
+            #line 1972 "Python/bytecodes.c"
             if (check_except_star_type_valid(tstate, match_type) < 0) {
-            #line 2770 "Python/generated_cases.c.h"
+            #line 2782 "Python/generated_cases.c.h"
                 Py_DECREF(exc_value);
                 Py_DECREF(match_type);
-            #line 1968 "Python/bytecodes.c"
+            #line 1974 "Python/bytecodes.c"
                 if (true) goto pop_2_error;
             }
 
@@ -2777,10 +2789,10 @@
             rest = NULL;
             int res = exception_group_match(exc_value, match_type,
                                             &match, &rest);
-            #line 2781 "Python/generated_cases.c.h"
+            #line 2793 "Python/generated_cases.c.h"
             Py_DECREF(exc_value);
             Py_DECREF(match_type);
-            #line 1976 "Python/bytecodes.c"
+            #line 1982 "Python/bytecodes.c"
             if (res < 0) goto pop_2_error;
 
             assert((match == NULL) == (rest == NULL));
@@ -2789,7 +2801,7 @@
             if (!Py_IsNone(match)) {
                 PyErr_SetHandledException(match);
             }
-            #line 2793 "Python/generated_cases.c.h"
+            #line 2805 "Python/generated_cases.c.h"
             stack_pointer[-1] = match;
             stack_pointer[-2] = rest;
             DISPATCH();
@@ -2799,21 +2811,21 @@
             PyObject *right = stack_pointer[-1];
             PyObject *left = stack_pointer[-2];
             PyObject *b;
-            #line 1987 "Python/bytecodes.c"
+            #line 1993 "Python/bytecodes.c"
             assert(PyExceptionInstance_Check(left));
             if (check_except_type_valid(tstate, right) < 0) {
-            #line 2806 "Python/generated_cases.c.h"
+            #line 2818 "Python/generated_cases.c.h"
                  Py_DECREF(right);
-            #line 1990 "Python/bytecodes.c"
+            #line 1996 "Python/bytecodes.c"
                  if (true) goto pop_1_error;
             }
 
             int res = PyErr_GivenExceptionMatches(left, right);
-            #line 2813 "Python/generated_cases.c.h"
+            #line 2825 "Python/generated_cases.c.h"
             Py_DECREF(right);
-            #line 1995 "Python/bytecodes.c"
+            #line 2001 "Python/bytecodes.c"
             b = Py_NewRef(res ? Py_True : Py_False);
-            #line 2817 "Python/generated_cases.c.h"
+            #line 2829 "Python/generated_cases.c.h"
             stack_pointer[-1] = b;
             DISPATCH();
         }
@@ -2822,15 +2834,15 @@
             PyObject *fromlist = stack_pointer[-1];
             PyObject *level = stack_pointer[-2];
             PyObject *res;
-            #line 1999 "Python/bytecodes.c"
+            #line 2005 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             res = import_name(tstate, frame, name, fromlist, level);
-            #line 2829 "Python/generated_cases.c.h"
+            #line 2841 "Python/generated_cases.c.h"
             Py_DECREF(level);
             Py_DECREF(fromlist);
-            #line 2002 "Python/bytecodes.c"
+            #line 2008 "Python/bytecodes.c"
             if (res == NULL) goto pop_2_error;
-            #line 2834 "Python/generated_cases.c.h"
+            #line 2846 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             DISPATCH();
@@ -2839,29 +2851,29 @@
         TARGET(IMPORT_FROM) {
             PyObject *from = stack_pointer[-1];
             PyObject *res;
-            #line 2006 "Python/bytecodes.c"
+            #line 2012 "Python/bytecodes.c"
             PyObject *name = GETITEM(frame->f_code->co_names, oparg);
             res = import_from(tstate, from, name);
             if (res == NULL) goto error;
-            #line 2847 "Python/generated_cases.c.h"
+            #line 2859 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             DISPATCH();
         }
 
         TARGET(JUMP_FORWARD) {
-            #line 2012 "Python/bytecodes.c"
+            #line 2018 "Python/bytecodes.c"
             JUMPBY(oparg);
-            #line 2856 "Python/generated_cases.c.h"
+            #line 2868 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(JUMP_BACKWARD) {
             PREDICTED(JUMP_BACKWARD);
-            #line 2016 "Python/bytecodes.c"
+            #line 2022 "Python/bytecodes.c"
             assert(oparg < INSTR_OFFSET());
             JUMPBY(-oparg);
-            #line 2865 "Python/generated_cases.c.h"
+            #line 2877 "Python/generated_cases.c.h"
             CHECK_EVAL_BREAKER();
             DISPATCH();
         }
@@ -2869,7 +2881,7 @@
         TARGET(POP_JUMP_IF_FALSE) {
             PREDICTED(POP_JUMP_IF_FALSE);
             PyObject *cond = stack_pointer[-1];
-            #line 2022 "Python/bytecodes.c"
+            #line 2028 "Python/bytecodes.c"
             if (Py_IsTrue(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
@@ -2879,9 +2891,9 @@
             }
             else {
                 int err = PyObject_IsTrue(cond);
-            #line 2883 "Python/generated_cases.c.h"
+            #line 2895 "Python/generated_cases.c.h"
                 Py_DECREF(cond);
-            #line 2032 "Python/bytecodes.c"
+            #line 2038 "Python/bytecodes.c"
                 if (err == 0) {
                     JUMPBY(oparg);
                 }
@@ -2889,14 +2901,14 @@
                     if (err < 0) goto pop_1_error;
                 }
             }
-            #line 2893 "Python/generated_cases.c.h"
+            #line 2905 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_TRUE) {
             PyObject *cond = stack_pointer[-1];
-            #line 2042 "Python/bytecodes.c"
+            #line 2048 "Python/bytecodes.c"
             if (Py_IsFalse(cond)) {
                 _Py_DECREF_NO_DEALLOC(cond);
             }
@@ -2906,9 +2918,9 @@
             }
             else {
                 int err = PyObject_IsTrue(cond);
-            #line 2910 "Python/generated_cases.c.h"
+            #line 2922 "Python/generated_cases.c.h"
                 Py_DECREF(cond);
-            #line 2052 "Python/bytecodes.c"
+            #line 2058 "Python/bytecodes.c"
                 if (err > 0) {
                     JUMPBY(oparg);
                 }
@@ -2916,67 +2928,67 @@
                     if (err < 0) goto pop_1_error;
                 }
             }
-            #line 2920 "Python/generated_cases.c.h"
+            #line 2932 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_NOT_NONE) {
             PyObject *value = stack_pointer[-1];
-            #line 2062 "Python/bytecodes.c"
+            #line 2068 "Python/bytecodes.c"
             if (!Py_IsNone(value)) {
-            #line 2929 "Python/generated_cases.c.h"
+            #line 2941 "Python/generated_cases.c.h"
                 Py_DECREF(value);
-            #line 2064 "Python/bytecodes.c"
+            #line 2070 "Python/bytecodes.c"
                 JUMPBY(oparg);
             }
             else {
                 _Py_DECREF_NO_DEALLOC(value);
             }
-            #line 2937 "Python/generated_cases.c.h"
+            #line 2949 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(POP_JUMP_IF_NONE) {
             PyObject *value = stack_pointer[-1];
-            #line 2072 "Python/bytecodes.c"
+            #line 2078 "Python/bytecodes.c"
             if (Py_IsNone(value)) {
                 _Py_DECREF_NO_DEALLOC(value);
                 JUMPBY(oparg);
             }
             else {
-            #line 2950 "Python/generated_cases.c.h"
+            #line 2962 "Python/generated_cases.c.h"
                 Py_DECREF(value);
-            #line 2078 "Python/bytecodes.c"
+            #line 2084 "Python/bytecodes.c"
             }
-            #line 2954 "Python/generated_cases.c.h"
+            #line 2966 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             DISPATCH();
         }
 
         TARGET(JUMP_BACKWARD_NO_INTERRUPT) {
-            #line 2082 "Python/bytecodes.c"
+            #line 2088 "Python/bytecodes.c"
             /* This bytecode is used in the `yield from` or `await` loop.
              * If there is an interrupt, we want it handled in the innermost
              * generator or coroutine, so we deliberately do not check it here.
              * (see bpo-30039).
              */
             JUMPBY(-oparg);
-            #line 2967 "Python/generated_cases.c.h"
+            #line 2979 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(GET_LEN) {
             PyObject *obj = stack_pointer[-1];
             PyObject *len_o;
-            #line 2091 "Python/bytecodes.c"
+            #line 2097 "Python/bytecodes.c"
             // PUSH(len(TOS))
             Py_ssize_t len_i = PyObject_Length(obj);
             if (len_i < 0) goto error;
             len_o = PyLong_FromSsize_t(len_i);
             if (len_o == NULL) goto error;
-            #line 2980 "Python/generated_cases.c.h"
+            #line 2992 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = len_o;
             DISPATCH();
@@ -2987,16 +2999,16 @@
             PyObject *type = stack_pointer[-2];
             PyObject *subject = stack_pointer[-3];
             PyObject *attrs;
-            #line 2099 "Python/bytecodes.c"
+            #line 2105 "Python/bytecodes.c"
             // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
             // None on failure.
             assert(PyTuple_CheckExact(names));
             attrs = match_class(tstate, subject, type, oparg, names);
-            #line 2996 "Python/generated_cases.c.h"
+            #line 3008 "Python/generated_cases.c.h"
             Py_DECREF(subject);
             Py_DECREF(type);
             Py_DECREF(names);
-            #line 2104 "Python/bytecodes.c"
+            #line 2110 "Python/bytecodes.c"
             if (attrs) {
                 assert(PyTuple_CheckExact(attrs));  // Success!
             }
@@ -3004,7 +3016,7 @@
                 if (_PyErr_Occurred(tstate)) goto pop_3_error;
                 attrs = Py_NewRef(Py_None);  // Failure!
             }
-            #line 3008 "Python/generated_cases.c.h"
+            #line 3020 "Python/generated_cases.c.h"
             STACK_SHRINK(2);
             stack_pointer[-1] = attrs;
             DISPATCH();
@@ -3013,10 +3025,10 @@
         TARGET(MATCH_MAPPING) {
             PyObject *subject = stack_pointer[-1];
             PyObject *res;
-            #line 2114 "Python/bytecodes.c"
+            #line 2120 "Python/bytecodes.c"
             int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
             res = Py_NewRef(match ? Py_True : Py_False);
-            #line 3020 "Python/generated_cases.c.h"
+            #line 3032 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             PREDICT(POP_JUMP_IF_FALSE);
@@ -3026,10 +3038,10 @@
         TARGET(MATCH_SEQUENCE) {
             PyObject *subject = stack_pointer[-1];
             PyObject *res;
-            #line 2120 "Python/bytecodes.c"
+            #line 2126 "Python/bytecodes.c"
             int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
             res = Py_NewRef(match ? Py_True : Py_False);
-            #line 3033 "Python/generated_cases.c.h"
+            #line 3045 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             PREDICT(POP_JUMP_IF_FALSE);
@@ -3040,11 +3052,11 @@
             PyObject *keys = stack_pointer[-1];
             PyObject *subject = stack_pointer[-2];
             PyObject *values_or_none;
-            #line 2126 "Python/bytecodes.c"
+            #line 2132 "Python/bytecodes.c"
             // On successful match, PUSH(values). Otherwise, PUSH(None).
             values_or_none = match_keys(tstate, subject, keys);
             if (values_or_none == NULL) goto error;
-            #line 3048 "Python/generated_cases.c.h"
+            #line 3060 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = values_or_none;
             DISPATCH();
@@ -3053,14 +3065,14 @@
         TARGET(GET_ITER) {
             PyObject *iterable = stack_pointer[-1];
             PyObject *iter;
-            #line 2132 "Python/bytecodes.c"
+            #line 2138 "Python/bytecodes.c"
             /* before: [obj]; after [getiter(obj)] */
             iter = PyObject_GetIter(iterable);
-            #line 3060 "Python/generated_cases.c.h"
+            #line 3072 "Python/generated_cases.c.h"
             Py_DECREF(iterable);
-            #line 2135 "Python/bytecodes.c"
+            #line 2141 "Python/bytecodes.c"
             if (iter == NULL) goto pop_1_error;
-            #line 3064 "Python/generated_cases.c.h"
+            #line 3076 "Python/generated_cases.c.h"
             stack_pointer[-1] = iter;
             DISPATCH();
         }
@@ -3068,7 +3080,7 @@
         TARGET(GET_YIELD_FROM_ITER) {
             PyObject *iterable = stack_pointer[-1];
             PyObject *iter;
-            #line 2139 "Python/bytecodes.c"
+            #line 2145 "Python/bytecodes.c"
             /* before: [obj]; after [getiter(obj)] */
             if (PyCoro_CheckExact(iterable)) {
                 /* `iterable` is a coroutine */
@@ -3091,11 +3103,11 @@
                 if (iter == NULL) {
                     goto error;
                 }
-            #line 3095 "Python/generated_cases.c.h"
+            #line 3107 "Python/generated_cases.c.h"
                 Py_DECREF(iterable);
-            #line 2162 "Python/bytecodes.c"
+            #line 2168 "Python/bytecodes.c"
             }
-            #line 3099 "Python/generated_cases.c.h"
+            #line 3111 "Python/generated_cases.c.h"
             stack_pointer[-1] = iter;
             PREDICT(LOAD_CONST);
             DISPATCH();
@@ -3106,7 +3118,7 @@
             static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size");
             PyObject *iter = stack_pointer[-1];
             PyObject *next;
-            #line 2181 "Python/bytecodes.c"
+            #line 2187 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyForIterCache *cache = (_PyForIterCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -3137,7 +3149,7 @@
                 DISPATCH();
             }
             // Common case: no jump, leave it to the code generator
-            #line 3141 "Python/generated_cases.c.h"
+            #line 3153 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = next;
             next_instr += 1;
@@ -3145,7 +3157,7 @@
         }
 
         TARGET(INSTRUMENTED_FOR_ITER) {
-            #line 2214 "Python/bytecodes.c"
+            #line 2220 "Python/bytecodes.c"
             _Py_CODEUNIT *here = next_instr-1;
             _Py_CODEUNIT *target;
             PyObject *iter = TOP();
@@ -3171,14 +3183,14 @@
                 target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1;
             }
             INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH);
-            #line 3175 "Python/generated_cases.c.h"
+            #line 3187 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(FOR_ITER_LIST) {
             PyObject *iter = stack_pointer[-1];
             PyObject *next;
-            #line 2242 "Python/bytecodes.c"
+            #line 2248 "Python/bytecodes.c"
             DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER);
             _PyListIterObject *it = (_PyListIterObject *)iter;
             STAT_INC(FOR_ITER, hit);
@@ -3198,7 +3210,7 @@
             DISPATCH();
         end_for_iter_list:
             // Common case: no jump, leave it to the code generator
-            #line 3202 "Python/generated_cases.c.h"
+            #line 3214 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = next;
             next_instr += 1;
@@ -3208,7 +3220,7 @@
         TARGET(FOR_ITER_TUPLE) {
             PyObject *iter = stack_pointer[-1];
             PyObject *next;
-            #line 2264 "Python/bytecodes.c"
+            #line 2270 "Python/bytecodes.c"
             _PyTupleIterObject *it = (_PyTupleIterObject *)iter;
             DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER);
             STAT_INC(FOR_ITER, hit);
@@ -3228,7 +3240,7 @@
             DISPATCH();
         end_for_iter_tuple:
             // Common case: no jump, leave it to the code generator
-            #line 3232 "Python/generated_cases.c.h"
+            #line 3244 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = next;
             next_instr += 1;
@@ -3238,7 +3250,7 @@
         TARGET(FOR_ITER_RANGE) {
             PyObject *iter = stack_pointer[-1];
             PyObject *next;
-            #line 2286 "Python/bytecodes.c"
+            #line 2292 "Python/bytecodes.c"
             _PyRangeIterObject *r = (_PyRangeIterObject *)iter;
             DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
             STAT_INC(FOR_ITER, hit);
@@ -3256,7 +3268,7 @@
             if (next == NULL) {
                 goto error;
             }
-            #line 3260 "Python/generated_cases.c.h"
+            #line 3272 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = next;
             next_instr += 1;
@@ -3265,7 +3277,7 @@
 
         TARGET(FOR_ITER_GEN) {
             PyObject *iter = stack_pointer[-1];
-            #line 2306 "Python/bytecodes.c"
+            #line 2312 "Python/bytecodes.c"
             PyGenObject *gen = (PyGenObject *)iter;
             DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER);
             DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
@@ -3280,14 +3292,14 @@
             assert(next_instr[oparg].op.code == END_FOR ||
                    next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
             DISPATCH_INLINED(gen_frame);
-            #line 3284 "Python/generated_cases.c.h"
+            #line 3296 "Python/generated_cases.c.h"
         }
 
         TARGET(BEFORE_ASYNC_WITH) {
             PyObject *mgr = stack_pointer[-1];
             PyObject *exit;
             PyObject *res;
-            #line 2323 "Python/bytecodes.c"
+            #line 2329 "Python/bytecodes.c"
             PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__));
             if (enter == NULL) {
                 if (!_PyErr_Occurred(tstate)) {
@@ -3310,16 +3322,16 @@
                 Py_DECREF(enter);
                 goto error;
             }
-            #line 3314 "Python/generated_cases.c.h"
+            #line 3326 "Python/generated_cases.c.h"
             Py_DECREF(mgr);
-            #line 2346 "Python/bytecodes.c"
+            #line 2352 "Python/bytecodes.c"
             res = _PyObject_CallNoArgs(enter);
             Py_DECREF(enter);
             if (res == NULL) {
                 Py_DECREF(exit);
                 if (true) goto pop_1_error;
             }
-            #line 3323 "Python/generated_cases.c.h"
+            #line 3335 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             stack_pointer[-2] = exit;
@@ -3331,7 +3343,7 @@
             PyObject *mgr = stack_pointer[-1];
             PyObject *exit;
             PyObject *res;
-            #line 2356 "Python/bytecodes.c"
+            #line 2362 "Python/bytecodes.c"
             /* pop the context manager, push its __exit__ and the
              * value returned from calling its __enter__
              */
@@ -3357,16 +3369,16 @@
                 Py_DECREF(enter);
                 goto error;
             }
-            #line 3361 "Python/generated_cases.c.h"
+            #line 3373 "Python/generated_cases.c.h"
             Py_DECREF(mgr);
-            #line 2382 "Python/bytecodes.c"
+            #line 2388 "Python/bytecodes.c"
             res = _PyObject_CallNoArgs(enter);
             Py_DECREF(enter);
             if (res == NULL) {
                 Py_DECREF(exit);
                 if (true) goto pop_1_error;
             }
-            #line 3370 "Python/generated_cases.c.h"
+            #line 3382 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             stack_pointer[-2] = exit;
@@ -3378,7 +3390,7 @@
             PyObject *lasti = stack_pointer[-3];
             PyObject *exit_func = stack_pointer[-4];
             PyObject *res;
-            #line 2391 "Python/bytecodes.c"
+            #line 2397 "Python/bytecodes.c"
             /* At the top of the stack are 4 values:
                - val: TOP = exc_info()
                - unused: SECOND = previous exception
@@ -3399,7 +3411,7 @@
             res = PyObject_Vectorcall(exit_func, stack + 1,
                     3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
             if (res == NULL) goto error;
-            #line 3403 "Python/generated_cases.c.h"
+            #line 3415 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = res;
             DISPATCH();
@@ -3408,7 +3420,7 @@
         TARGET(PUSH_EXC_INFO) {
             PyObject *new_exc = stack_pointer[-1];
             PyObject *prev_exc;
-            #line 2414 "Python/bytecodes.c"
+            #line 2420 "Python/bytecodes.c"
             _PyErr_StackItem *exc_info = tstate->exc_info;
             if (exc_info->exc_value != NULL) {
                 prev_exc = exc_info->exc_value;
@@ -3418,7 +3430,7 @@
             }
             assert(PyExceptionInstance_Check(new_exc));
             exc_info->exc_value = Py_NewRef(new_exc);
-            #line 3422 "Python/generated_cases.c.h"
+            #line 3434 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = new_exc;
             stack_pointer[-2] = prev_exc;
@@ -3432,7 +3444,7 @@
             uint32_t type_version = read_u32(&next_instr[1].cache);
             uint32_t keys_version = read_u32(&next_instr[3].cache);
             PyObject *descr = read_obj(&next_instr[5].cache);
-            #line 2426 "Python/bytecodes.c"
+            #line 2432 "Python/bytecodes.c"
             /* Cached method object */
             PyTypeObject *self_cls = Py_TYPE(self);
             assert(type_version != 0);
@@ -3449,7 +3461,7 @@
             assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR));
             res = self;
             assert(oparg & 1);
-            #line 3453 "Python/generated_cases.c.h"
+            #line 3465 "Python/generated_cases.c.h"
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
             if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3463,7 +3475,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             PyObject *descr = read_obj(&next_instr[5].cache);
-            #line 2445 "Python/bytecodes.c"
+            #line 2451 "Python/bytecodes.c"
             PyTypeObject *self_cls = Py_TYPE(self);
             DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
             assert(self_cls->tp_dictoffset == 0);
@@ -3473,7 +3485,7 @@
             res2 = Py_NewRef(descr);
             res = self;
             assert(oparg & 1);
-            #line 3477 "Python/generated_cases.c.h"
+            #line 3489 "Python/generated_cases.c.h"
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
             if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3487,7 +3499,7 @@
             PyObject *res;
             uint32_t type_version = read_u32(&next_instr[1].cache);
             PyObject *descr = read_obj(&next_instr[5].cache);
-            #line 2457 "Python/bytecodes.c"
+            #line 2463 "Python/bytecodes.c"
             PyTypeObject *self_cls = Py_TYPE(self);
             DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
             Py_ssize_t dictoffset = self_cls->tp_dictoffset;
@@ -3501,7 +3513,7 @@
             res2 = Py_NewRef(descr);
             res = self;
             assert(oparg & 1);
-            #line 3505 "Python/generated_cases.c.h"
+            #line 3517 "Python/generated_cases.c.h"
             STACK_GROW(((oparg & 1) ? 1 : 0));
             stack_pointer[-1] = res;
             if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3510,16 +3522,16 @@
         }
 
         TARGET(KW_NAMES) {
-            #line 2473 "Python/bytecodes.c"
+            #line 2479 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts));
             kwnames = GETITEM(frame->f_code->co_consts, oparg);
-            #line 3518 "Python/generated_cases.c.h"
+            #line 3530 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_CALL) {
-            #line 2479 "Python/bytecodes.c"
+            #line 2485 "Python/bytecodes.c"
             int is_meth = PEEK(oparg+2) != NULL;
             int total_args = oparg + is_meth;
             PyObject *function = PEEK(total_args + 1);
@@ -3532,7 +3544,7 @@
             _PyCallCache *cache = (_PyCallCache *)next_instr;
             INCREMENT_ADAPTIVE_COUNTER(cache->counter);
             GO_TO_INSTRUCTION(CALL);
-            #line 3536 "Python/generated_cases.c.h"
+            #line 3548 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL) {
@@ -3542,7 +3554,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2524 "Python/bytecodes.c"
+            #line 2530 "Python/bytecodes.c"
             int is_meth = method != NULL;
             int total_args = oparg;
             if (is_meth) {
@@ -3624,7 +3636,7 @@
                 Py_DECREF(args[i]);
             }
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3628 "Python/generated_cases.c.h"
+            #line 3640 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3636,7 +3648,7 @@
         TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
-            #line 2612 "Python/bytecodes.c"
+            #line 2618 "Python/bytecodes.c"
             DEOPT_IF(method != NULL, CALL);
             DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
             STAT_INC(CALL, hit);
@@ -3646,7 +3658,7 @@
             PEEK(oparg + 2) = Py_NewRef(meth);  // method
             Py_DECREF(callable);
             GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
-            #line 3650 "Python/generated_cases.c.h"
+            #line 3662 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL_PY_EXACT_ARGS) {
@@ -3655,7 +3667,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             uint32_t func_version = read_u32(&next_instr[1].cache);
-            #line 2624 "Python/bytecodes.c"
+            #line 2630 "Python/bytecodes.c"
             assert(kwnames == NULL);
             DEOPT_IF(tstate->interp->eval_frame, CALL);
             int is_meth = method != NULL;
@@ -3681,7 +3693,7 @@
             JUMPBY(INLINE_CACHE_ENTRIES_CALL);
             frame->return_offset = 0;
             DISPATCH_INLINED(new_frame);
-            #line 3685 "Python/generated_cases.c.h"
+            #line 3697 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL_PY_WITH_DEFAULTS) {
@@ -3689,7 +3701,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             uint32_t func_version = read_u32(&next_instr[1].cache);
-            #line 2652 "Python/bytecodes.c"
+            #line 2658 "Python/bytecodes.c"
             assert(kwnames == NULL);
             DEOPT_IF(tstate->interp->eval_frame, CALL);
             int is_meth = method != NULL;
@@ -3725,7 +3737,7 @@
             JUMPBY(INLINE_CACHE_ENTRIES_CALL);
             frame->return_offset = 0;
             DISPATCH_INLINED(new_frame);
-            #line 3729 "Python/generated_cases.c.h"
+            #line 3741 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL_NO_KW_TYPE_1) {
@@ -3733,7 +3745,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *null = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2690 "Python/bytecodes.c"
+            #line 2696 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg == 1);
             DEOPT_IF(null != NULL, CALL);
@@ -3743,7 +3755,7 @@
             res = Py_NewRef(Py_TYPE(obj));
             Py_DECREF(obj);
             Py_DECREF(&PyType_Type);  // I.e., callable
-            #line 3747 "Python/generated_cases.c.h"
+            #line 3759 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3756,7 +3768,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *null = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2702 "Python/bytecodes.c"
+            #line 2708 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg == 1);
             DEOPT_IF(null != NULL, CALL);
@@ -3767,7 +3779,7 @@
             Py_DECREF(arg);
             Py_DECREF(&PyUnicode_Type);  // I.e., callable
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3771 "Python/generated_cases.c.h"
+            #line 3783 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3781,7 +3793,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *null = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2716 "Python/bytecodes.c"
+            #line 2722 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg == 1);
             DEOPT_IF(null != NULL, CALL);
@@ -3792,7 +3804,7 @@
             Py_DECREF(arg);
             Py_DECREF(&PyTuple_Type);  // I.e., tuple
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3796 "Python/generated_cases.c.h"
+            #line 3808 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3806,7 +3818,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2730 "Python/bytecodes.c"
+            #line 2736 "Python/bytecodes.c"
             int is_meth = method != NULL;
             int total_args = oparg;
             if (is_meth) {
@@ -3828,7 +3840,7 @@
             }
             Py_DECREF(tp);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3832 "Python/generated_cases.c.h"
+            #line 3844 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3842,7 +3854,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2755 "Python/bytecodes.c"
+            #line 2761 "Python/bytecodes.c"
             /* Builtin METH_O functions */
             assert(kwnames == NULL);
             int is_meth = method != NULL;
@@ -3870,7 +3882,7 @@
             Py_DECREF(arg);
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3874 "Python/generated_cases.c.h"
+            #line 3886 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3884,7 +3896,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2786 "Python/bytecodes.c"
+            #line 2792 "Python/bytecodes.c"
             /* Builtin METH_FASTCALL functions, without keywords */
             assert(kwnames == NULL);
             int is_meth = method != NULL;
@@ -3916,7 +3928,7 @@
                    'invalid'). In those cases an exception is set, so we must
                    handle it.
                 */
-            #line 3920 "Python/generated_cases.c.h"
+            #line 3932 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3930,7 +3942,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2821 "Python/bytecodes.c"
+            #line 2827 "Python/bytecodes.c"
             /* Builtin METH_FASTCALL | METH_KEYWORDS functions */
             int is_meth = method != NULL;
             int total_args = oparg;
@@ -3962,7 +3974,7 @@
             }
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 3966 "Python/generated_cases.c.h"
+            #line 3978 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -3976,7 +3988,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2856 "Python/bytecodes.c"
+            #line 2862 "Python/bytecodes.c"
             assert(kwnames == NULL);
             /* len(o) */
             int is_meth = method != NULL;
@@ -4001,7 +4013,7 @@
             Py_DECREF(callable);
             Py_DECREF(arg);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4005 "Python/generated_cases.c.h"
+            #line 4017 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4014,7 +4026,7 @@
             PyObject *callable = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2883 "Python/bytecodes.c"
+            #line 2889 "Python/bytecodes.c"
             assert(kwnames == NULL);
             /* isinstance(o, o2) */
             int is_meth = method != NULL;
@@ -4041,7 +4053,7 @@
             Py_DECREF(cls);
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4045 "Python/generated_cases.c.h"
+            #line 4057 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4053,7 +4065,7 @@
             PyObject **args = (stack_pointer - oparg);
             PyObject *self = stack_pointer[-(1 + oparg)];
             PyObject *method = stack_pointer[-(2 + oparg)];
-            #line 2913 "Python/bytecodes.c"
+            #line 2919 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg == 1);
             assert(method != NULL);
@@ -4071,14 +4083,14 @@
             JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1);
             assert(next_instr[-1].op.code == POP_TOP);
             DISPATCH();
-            #line 4075 "Python/generated_cases.c.h"
+            #line 4087 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
             PyObject **args = (stack_pointer - oparg);
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2933 "Python/bytecodes.c"
+            #line 2939 "Python/bytecodes.c"
             assert(kwnames == NULL);
             int is_meth = method != NULL;
             int total_args = oparg;
@@ -4109,7 +4121,7 @@
             Py_DECREF(arg);
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4113 "Python/generated_cases.c.h"
+            #line 4125 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4122,7 +4134,7 @@
             PyObject **args = (stack_pointer - oparg);
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2967 "Python/bytecodes.c"
+            #line 2973 "Python/bytecodes.c"
             int is_meth = method != NULL;
             int total_args = oparg;
             if (is_meth) {
@@ -4151,7 +4163,7 @@
             }
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4155 "Python/generated_cases.c.h"
+            #line 4167 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4164,7 +4176,7 @@
             PyObject **args = (stack_pointer - oparg);
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 2999 "Python/bytecodes.c"
+            #line 3005 "Python/bytecodes.c"
             assert(kwnames == NULL);
             assert(oparg == 0 || oparg == 1);
             int is_meth = method != NULL;
@@ -4193,7 +4205,7 @@
             Py_DECREF(self);
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4197 "Python/generated_cases.c.h"
+            #line 4209 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4206,7 +4218,7 @@
             PyObject **args = (stack_pointer - oparg);
             PyObject *method = stack_pointer[-(2 + oparg)];
             PyObject *res;
-            #line 3031 "Python/bytecodes.c"
+            #line 3037 "Python/bytecodes.c"
             assert(kwnames == NULL);
             int is_meth = method != NULL;
             int total_args = oparg;
@@ -4234,7 +4246,7 @@
             }
             Py_DECREF(callable);
             if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
-            #line 4238 "Python/generated_cases.c.h"
+            #line 4250 "Python/generated_cases.c.h"
             STACK_SHRINK(oparg);
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
@@ -4244,9 +4256,9 @@
         }
 
         TARGET(INSTRUMENTED_CALL_FUNCTION_EX) {
-            #line 3062 "Python/bytecodes.c"
+            #line 3068 "Python/bytecodes.c"
             GO_TO_INSTRUCTION(CALL_FUNCTION_EX);
-            #line 4250 "Python/generated_cases.c.h"
+            #line 4262 "Python/generated_cases.c.h"
         }
 
         TARGET(CALL_FUNCTION_EX) {
@@ -4255,7 +4267,7 @@
             PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))];
             PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))];
             PyObject *result;
-            #line 3066 "Python/bytecodes.c"
+            #line 3072 "Python/bytecodes.c"
             // DICT_MERGE is called before this opcode if there are kwargs.
             // It converts all dict subtypes in kwargs into regular dicts.
             assert(kwargs == NULL || PyDict_CheckExact(kwargs));
@@ -4317,14 +4329,14 @@
                 }
                 result = PyObject_Call(func, callargs, kwargs);
             }
-            #line 4321 "Python/generated_cases.c.h"
+            #line 4333 "Python/generated_cases.c.h"
             Py_DECREF(func);
             Py_DECREF(callargs);
             Py_XDECREF(kwargs);
-            #line 3128 "Python/bytecodes.c"
+            #line 3134 "Python/bytecodes.c"
             assert(PEEK(3 + (oparg & 1)) == NULL);
             if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; }
-            #line 4328 "Python/generated_cases.c.h"
+            #line 4340 "Python/generated_cases.c.h"
             STACK_SHRINK(((oparg & 1) ? 1 : 0));
             STACK_SHRINK(2);
             stack_pointer[-1] = result;
@@ -4339,7 +4351,7 @@
             PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL;
             PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL;
             PyObject *func;
-            #line 3138 "Python/bytecodes.c"
+            #line 3144 "Python/bytecodes.c"
 
             PyFunctionObject *func_obj = (PyFunctionObject *)
                 PyFunction_New(codeobj, GLOBALS());
@@ -4368,14 +4380,14 @@
 
             func_obj->func_version = ((PyCodeObject *)codeobj)->co_version;
             func = (PyObject *)func_obj;
-            #line 4372 "Python/generated_cases.c.h"
+            #line 4384 "Python/generated_cases.c.h"
             STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0));
             stack_pointer[-1] = func;
             DISPATCH();
         }
 
         TARGET(RETURN_GENERATOR) {
-            #line 3169 "Python/bytecodes.c"
+            #line 3175 "Python/bytecodes.c"
             assert(PyFunction_Check(frame->f_funcobj));
             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
@@ -4396,7 +4408,7 @@
             frame = cframe.current_frame = prev;
             _PyFrame_StackPush(frame, (PyObject *)gen);
             goto resume_frame;
-            #line 4400 "Python/generated_cases.c.h"
+            #line 4412 "Python/generated_cases.c.h"
         }
 
         TARGET(BUILD_SLICE) {
@@ -4404,15 +4416,15 @@
             PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))];
             PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))];
             PyObject *slice;
-            #line 3192 "Python/bytecodes.c"
+            #line 3198 "Python/bytecodes.c"
             slice = PySlice_New(start, stop, step);
-            #line 4410 "Python/generated_cases.c.h"
+            #line 4422 "Python/generated_cases.c.h"
             Py_DECREF(start);
             Py_DECREF(stop);
             Py_XDECREF(step);
-            #line 3194 "Python/bytecodes.c"
+            #line 3200 "Python/bytecodes.c"
             if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; }
-            #line 4416 "Python/generated_cases.c.h"
+            #line 4428 "Python/generated_cases.c.h"
             STACK_SHRINK(((oparg == 3) ? 1 : 0));
             STACK_SHRINK(1);
             stack_pointer[-1] = slice;
@@ -4423,7 +4435,7 @@
             PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL;
             PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))];
             PyObject *result;
-            #line 3198 "Python/bytecodes.c"
+            #line 3204 "Python/bytecodes.c"
             /* Handles f-string value formatting. */
             PyObject *(*conv_fn)(PyObject *);
             int which_conversion = oparg & FVC_MASK;
@@ -4458,7 +4470,7 @@
             Py_DECREF(value);
             Py_XDECREF(fmt_spec);
             if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; }
-            #line 4462 "Python/generated_cases.c.h"
+            #line 4474 "Python/generated_cases.c.h"
             STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0));
             stack_pointer[-1] = result;
             DISPATCH();
@@ -4467,10 +4479,10 @@
         TARGET(COPY) {
             PyObject *bottom = stack_pointer[-(1 + (oparg-1))];
             PyObject *top;
-            #line 3235 "Python/bytecodes.c"
+            #line 3241 "Python/bytecodes.c"
             assert(oparg > 0);
             top = Py_NewRef(bottom);
-            #line 4474 "Python/generated_cases.c.h"
+            #line 4486 "Python/generated_cases.c.h"
             STACK_GROW(1);
             stack_pointer[-1] = top;
             DISPATCH();
@@ -4482,7 +4494,7 @@
             PyObject *rhs = stack_pointer[-1];
             PyObject *lhs = stack_pointer[-2];
             PyObject *res;
-            #line 3240 "Python/bytecodes.c"
+            #line 3246 "Python/bytecodes.c"
             #if ENABLE_SPECIALIZATION
             _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
             if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
@@ -4497,12 +4509,12 @@
             assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops));
             assert(binary_ops[oparg]);
             res = binary_ops[oparg](lhs, rhs);
-            #line 4501 "Python/generated_cases.c.h"
+            #line 4513 "Python/generated_cases.c.h"
             Py_DECREF(lhs);
             Py_DECREF(rhs);
-            #line 3255 "Python/bytecodes.c"
+            #line 3261 "Python/bytecodes.c"
             if (res == NULL) goto pop_2_error;
-            #line 4506 "Python/generated_cases.c.h"
+            #line 4518 "Python/generated_cases.c.h"
             STACK_SHRINK(1);
             stack_pointer[-1] = res;
             next_instr += 1;
@@ -4512,16 +4524,16 @@
         TARGET(SWAP) {
             PyObject *top = stack_pointer[-1];
             PyObject *bottom = stack_pointer[-(2 + (oparg-2))];
-            #line 3260 "Python/bytecodes.c"
+            #line 3266 "Python/bytecodes.c"
             assert(oparg >= 2);
-            #line 4518 "Python/generated_cases.c.h"
+            #line 4530 "Python/generated_cases.c.h"
             stack_pointer[-1] = bottom;
             stack_pointer[-(2 + (oparg-2))] = top;
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_LINE) {
-            #line 3264 "Python/bytecodes.c"
+            #line 3270 "Python/bytecodes.c"
             _Py_CODEUNIT *here = next_instr-1;
             _PyFrame_SetStackPointer(frame, stack_pointer);
             int original_opcode = _Py_call_instrumentation_line(
@@ -4541,11 +4553,11 @@
             }
             opcode = original_opcode;
             DISPATCH_GOTO();
-            #line 4545 "Python/generated_cases.c.h"
+            #line 4557 "Python/generated_cases.c.h"
         }
 
         TARGET(INSTRUMENTED_INSTRUCTION) {
-            #line 3286 "Python/bytecodes.c"
+            #line 3292 "Python/bytecodes.c"
             int next_opcode = _Py_call_instrumentation_instruction(
                 tstate, frame, next_instr-1);
             if (next_opcode < 0) goto error;
@@ -4557,26 +4569,26 @@
             assert(next_opcode > 0 && next_opcode < 256);
             opcode = next_opcode;
             DISPATCH_GOTO();
-            #line 4561 "Python/generated_cases.c.h"
+            #line 4573 "Python/generated_cases.c.h"
         }
 
         TARGET(INSTRUMENTED_JUMP_FORWARD) {
-            #line 3300 "Python/bytecodes.c"
+            #line 3306 "Python/bytecodes.c"
             INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP);
-            #line 4567 "Python/generated_cases.c.h"
+            #line 4579 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_JUMP_BACKWARD) {
-            #line 3304 "Python/bytecodes.c"
+            #line 3310 "Python/bytecodes.c"
             INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP);
-            #line 4574 "Python/generated_cases.c.h"
+            #line 4586 "Python/generated_cases.c.h"
             CHECK_EVAL_BREAKER();
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) {
-            #line 3309 "Python/bytecodes.c"
+            #line 3315 "Python/bytecodes.c"
             PyObject *cond = POP();
             int err = PyObject_IsTrue(cond);
             Py_DECREF(cond);
@@ -4585,12 +4597,12 @@
             assert(err == 0 || err == 1);
             int offset = err*oparg;
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
-            #line 4589 "Python/generated_cases.c.h"
+            #line 4601 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) {
-            #line 3320 "Python/bytecodes.c"
+            #line 3326 "Python/bytecodes.c"
             PyObject *cond = POP();
             int err = PyObject_IsTrue(cond);
             Py_DECREF(cond);
@@ -4599,12 +4611,12 @@
             assert(err == 0 || err == 1);
             int offset = (1-err)*oparg;
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
-            #line 4603 "Python/generated_cases.c.h"
+            #line 4615 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) {
-            #line 3331 "Python/bytecodes.c"
+            #line 3337 "Python/bytecodes.c"
             PyObject *value = POP();
             _Py_CODEUNIT *here = next_instr-1;
             int offset;
@@ -4617,12 +4629,12 @@
                 offset = 0;
             }
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
-            #line 4621 "Python/generated_cases.c.h"
+            #line 4633 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) {
-            #line 3346 "Python/bytecodes.c"
+            #line 3352 "Python/bytecodes.c"
             PyObject *value = POP();
             _Py_CODEUNIT *here = next_instr-1;
             int offset;
@@ -4635,30 +4647,30 @@
                  offset = oparg;
             }
             INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
-            #line 4639 "Python/generated_cases.c.h"
+            #line 4651 "Python/generated_cases.c.h"
             DISPATCH();
         }
 
         TARGET(EXTENDED_ARG) {
-            #line 3361 "Python/bytecodes.c"
+            #line 3367 "Python/bytecodes.c"
             assert(oparg);
             opcode = next_instr->op.code;
             oparg = oparg << 8 | next_instr->op.arg;
             PRE_DISPATCH_GOTO();
             DISPATCH_GOTO();
-            #line 4650 "Python/generated_cases.c.h"
+            #line 4662 "Python/generated_cases.c.h"
         }
 
         TARGET(CACHE) {
-            #line 3369 "Python/bytecodes.c"
+            #line 3375 "Python/bytecodes.c"
             assert(0 && "Executing a cache.");
             Py_UNREACHABLE();
-            #line 4657 "Python/generated_cases.c.h"
+            #line 4669 "Python/generated_cases.c.h"
         }
 
         TARGET(RESERVED) {
-            #line 3374 "Python/bytecodes.c"
+            #line 3380 "Python/bytecodes.c"
             assert(0 && "Executing RESERVED instruction.");
             Py_UNREACHABLE();
-            #line 4664 "Python/generated_cases.c.h"
+            #line 4676 "Python/generated_cases.c.h"
         }
diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h
index 77f0ae0c1a4c30..c1a6ed4c18ab0a 100644
--- a/Python/opcode_metadata.h
+++ b/Python/opcode_metadata.h
@@ -21,6 +21,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
             return 0;
         case LOAD_FAST:
             return 0;
+        case LOAD_FAST_AND_CLEAR:
+            return 0;
         case LOAD_CONST:
             return 0;
         case STORE_FAST:
@@ -409,6 +411,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
             return 1;
         case LOAD_FAST:
             return 1;
+        case LOAD_FAST_AND_CLEAR:
+            return 1;
         case LOAD_CONST:
             return 1;
         case STORE_FAST:
@@ -795,6 +799,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
     [LOAD_CLOSURE] = { true, INSTR_FMT_IB },
     [LOAD_FAST_CHECK] = { true, INSTR_FMT_IB },
     [LOAD_FAST] = { true, INSTR_FMT_IB },
+    [LOAD_FAST_AND_CLEAR] = { true, INSTR_FMT_IB },
     [LOAD_CONST] = { true, INSTR_FMT_IB },
     [STORE_FAST] = { true, INSTR_FMT_IB },
     [LOAD_FAST__LOAD_FAST] = { true, INSTR_FMT_IBIB },
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index 042cee222f705c..00f15ff98da418 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -142,7 +142,7 @@ static void *opcode_targets[256] = {
     &&TARGET_JUMP_BACKWARD,
     &&TARGET_LOAD_SUPER_ATTR,
     &&TARGET_CALL_FUNCTION_EX,
-    &&TARGET_STORE_FAST__LOAD_FAST,
+    &&TARGET_LOAD_FAST_AND_CLEAR,
     &&TARGET_EXTENDED_ARG,
     &&TARGET_LIST_APPEND,
     &&TARGET_SET_ADD,
@@ -152,24 +152,24 @@ static void *opcode_targets[256] = {
     &&TARGET_YIELD_VALUE,
     &&TARGET_RESUME,
     &&TARGET_MATCH_CLASS,
+    &&TARGET_STORE_FAST__LOAD_FAST,
     &&TARGET_STORE_FAST__STORE_FAST,
-    &&TARGET_STORE_SUBSCR_DICT,
     &&TARGET_FORMAT_VALUE,
     &&TARGET_BUILD_CONST_KEY_MAP,
     &&TARGET_BUILD_STRING,
+    &&TARGET_STORE_SUBSCR_DICT,
     &&TARGET_STORE_SUBSCR_LIST_INT,
     &&TARGET_UNPACK_SEQUENCE_LIST,
     &&TARGET_UNPACK_SEQUENCE_TUPLE,
-    &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
     &&TARGET_LIST_EXTEND,
     &&TARGET_SET_UPDATE,
     &&TARGET_DICT_MERGE,
     &&TARGET_DICT_UPDATE,
+    &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
     &&TARGET_SEND_GEN,
     &&_unknown_opcode,
     &&_unknown_opcode,
     &&_unknown_opcode,
-    &&_unknown_opcode,
     &&TARGET_CALL,
     &&TARGET_KW_NAMES,
     &&TARGET_CALL_INTRINSIC_1,
diff --git a/Python/symtable.c b/Python/symtable.c
index df7473943f3fc1..6e74d764245a57 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -103,6 +103,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
     ste->ste_comprehension = NoComprehension;
     ste->ste_returns_value = 0;
     ste->ste_needs_class_closure = 0;
+    ste->ste_comp_inlined = 0;
     ste->ste_comp_iter_target = 0;
     ste->ste_comp_iter_expr = 0;
 
@@ -558,6 +559,67 @@ analyze_name(PySTEntryObject *ste, PyObject *scopes, PyObject *name, long flags,
     return 1;
 }
 
+static int
+is_free_in_any_child(PySTEntryObject *entry, PyObject *key)
+{
+    for (Py_ssize_t i = 0; i < PyList_GET_SIZE(entry->ste_children); i++) {
+        PySTEntryObject *child_ste = (PySTEntryObject *)PyList_GET_ITEM(
+            entry->ste_children, i);
+        long scope = _PyST_GetScope(child_ste, key);
+        if (scope == FREE) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int
+inline_comprehension(PySTEntryObject *ste, PySTEntryObject *comp,
+                     PyObject *scopes, PyObject *comp_free)
+{
+    PyObject *k, *v;
+    Py_ssize_t pos = 0;
+    while (PyDict_Next(comp->ste_symbols, &pos, &k, &v)) {
+        // skip comprehension parameter
+        long comp_flags = PyLong_AS_LONG(v);
+        if (comp_flags & DEF_PARAM) {
+            assert(_PyUnicode_EqualToASCIIString(k, ".0"));
+            continue;
+        }
+        int scope = (comp_flags >> SCOPE_OFFSET) & SCOPE_MASK;
+        int only_flags = comp_flags & ((1 << SCOPE_OFFSET) - 1);
+        PyObject *existing = PyDict_GetItemWithError(ste->ste_symbols, k);
+        if (existing == NULL && PyErr_Occurred()) {
+            return 0;
+        }
+        if (!existing) {
+            // name does not exist in scope, copy from comprehension
+            assert(scope != FREE || PySet_Contains(comp_free, k) == 1);
+            PyObject *v_flags = PyLong_FromLong(only_flags);
+            if (v_flags == NULL) {
+                return 0;
+            }
+            int ok = PyDict_SetItem(ste->ste_symbols, k, v_flags);
+            Py_DECREF(v_flags);
+            if (ok < 0) {
+                return 0;
+            }
+            SET_SCOPE(scopes, k, scope);
+        }
+        else {
+            // free vars in comprehension that are locals in outer scope can
+            // now simply be locals, unless they are free in comp children
+            if ((PyLong_AsLong(existing) & DEF_BOUND) &&
+                    !is_free_in_any_child(comp, k)) {
+                if (PySet_Discard(comp_free, k) < 0) {
+                    return 0;
+                }
+            }
+        }
+    }
+    return 1;
+}
+
 #undef SET_SCOPE
 
 /* If a name is defined in free and also in locals, then this block
@@ -727,17 +789,17 @@ update_symbols(PyObject *symbols, PyObject *scopes,
 
 static int
 analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
-                    PyObject *global, PyObject* child_free);
+                    PyObject *global, PyObject **child_free);
 
 static int
 analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
               PyObject *global)
 {
     PyObject *name, *v, *local = NULL, *scopes = NULL, *newbound = NULL;
-    PyObject *newglobal = NULL, *newfree = NULL, *allfree = NULL;
+    PyObject *newglobal = NULL, *newfree = NULL;
     PyObject *temp;
-    int i, success = 0;
-    Py_ssize_t pos = 0;
+    int success = 0;
+    Py_ssize_t i, pos = 0;
 
     local = PySet_New(NULL);  /* collect new names bound in block */
     if (!local)
@@ -746,8 +808,8 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
     if (!scopes)
         goto error;
 
-    /* Allocate new global and bound variable dictionaries.  These
-       dictionaries hold the names visible in nested blocks.  For
+    /* Allocate new global, bound and free variable sets.  These
+       sets hold the names visible in nested blocks.  For
        ClassBlocks, the bound and global names are initialized
        before analyzing names, because class bindings aren't
        visible in methods.  For other blocks, they are initialized
@@ -826,28 +888,55 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
 
        newbound, newglobal now contain the names visible in
        nested blocks.  The free variables in the children will
-       be collected in allfree.
+       be added to newfree.
     */
-    allfree = PySet_New(NULL);
-    if (!allfree)
-        goto error;
     for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) {
+        PyObject *child_free = NULL;
         PyObject *c = PyList_GET_ITEM(ste->ste_children, i);
         PySTEntryObject* entry;
         assert(c && PySTEntry_Check(c));
         entry = (PySTEntryObject*)c;
+
+        // we inline all non-generator-expression comprehensions
+        int inline_comp =
+            entry->ste_comprehension &&
+            !entry->ste_generator;
+
         if (!analyze_child_block(entry, newbound, newfree, newglobal,
-                                 allfree))
+                                 &child_free))
+        {
             goto error;
+        }
+        if (inline_comp) {
+            if (!inline_comprehension(ste, entry, scopes, child_free)) {
+                Py_DECREF(child_free);
+                goto error;
+            }
+            entry->ste_comp_inlined = 1;
+        }
+        temp = PyNumber_InPlaceOr(newfree, child_free);
+        Py_DECREF(child_free);
+        if (!temp)
+            goto error;
+        Py_DECREF(temp);
         /* Check if any children have free variables */
         if (entry->ste_free || entry->ste_child_free)
             ste->ste_child_free = 1;
     }
 
-    temp = PyNumber_InPlaceOr(newfree, allfree);
-    if (!temp)
-        goto error;
-    Py_DECREF(temp);
+    /* Splice children of inlined comprehensions into our children list */
+    for (i = PyList_GET_SIZE(ste->ste_children) - 1; i >= 0; --i) {
+        PyObject* c = PyList_GET_ITEM(ste->ste_children, i);
+        PySTEntryObject* entry;
+        assert(c && PySTEntry_Check(c));
+        entry = (PySTEntryObject*)c;
+        if (entry->ste_comp_inlined &&
+            PyList_SetSlice(ste->ste_children, i, i + 1,
+                            entry->ste_children) < 0)
+        {
+            goto error;
+        }
+    }
 
     /* Check if any local variables must be converted to cell variables */
     if (ste->ste_type == FunctionBlock && !analyze_cells(scopes, newfree))
@@ -870,7 +959,6 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
     Py_XDECREF(newbound);
     Py_XDECREF(newglobal);
     Py_XDECREF(newfree);
-    Py_XDECREF(allfree);
     if (!success)
         assert(PyErr_Occurred());
     return success;
@@ -878,16 +966,15 @@ analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free,
 
 static int
 analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
-                    PyObject *global, PyObject* child_free)
+                    PyObject *global, PyObject** child_free)
 {
     PyObject *temp_bound = NULL, *temp_global = NULL, *temp_free = NULL;
-    PyObject *temp;
 
-    /* Copy the bound and global dictionaries.
+    /* Copy the bound/global/free sets.
 
-       These dictionaries are used by all blocks enclosed by the
+       These sets are used by all blocks enclosed by the
        current block.  The analyze_block() call modifies these
-       dictionaries.
+       sets.
 
     */
     temp_bound = PySet_New(bound);
@@ -902,12 +989,8 @@ analyze_child_block(PySTEntryObject *entry, PyObject *bound, PyObject *free,
 
     if (!analyze_block(entry, temp_bound, temp_free, temp_global))
         goto error;
-    temp = PyNumber_InPlaceOr(child_free, temp_free);
-    if (!temp)
-        goto error;
-    Py_DECREF(temp);
+    *child_free = temp_free;
     Py_DECREF(temp_bound);
-    Py_DECREF(temp_free);
     Py_DECREF(temp_global);
     return 1;
  error:
@@ -2216,4 +2299,3 @@ _Py_Mangle(PyObject *privateobj, PyObject *ident)
     assert(_PyUnicode_CheckConsistency(result, 1));
     return result;
 }
-

From 2866e030f01dc3ff08de32857fa77d52468b676b Mon Sep 17 00:00:00 2001
From: Jacob Bower <1978924+jbower-fb@users.noreply.github.com>
Date: Tue, 9 May 2023 10:09:16 -0700
Subject: [PATCH 35/35] gh-97696 Add documentation for get_coro() behavior with
 eager tasks (#104304)

---
 Doc/library/asyncio-task.rst | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index b2d7362a9de213..fe8d028150403d 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -527,6 +527,8 @@ Running Tasks Concurrently
       and there is no running event loop.
 
 
+.. _eager-task-factory:
+
 Eager Task Factory
 ==================
 
@@ -1174,8 +1176,17 @@ Task Object
 
       Return the coroutine object wrapped by the :class:`Task`.
 
+      .. note::
+
+         This will return ``None`` for Tasks which have already
+         completed eagerly. See the :ref:`Eager Task Factory <eager-task-factory>`.
+
       .. versionadded:: 3.8
 
+      .. versionchanged:: 3.12
+
+         Newly added eager task execution means result may be ``None``.
+
    .. method:: get_context()
 
       Return the :class:`contextvars.Context` object