From bc7c102f3462a9f014f3ac2546acfb471b2a7eae Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 4 May 2026 13:49:07 +0200 Subject: [PATCH 01/18] gh-149231: tomllib: Limit the number of parts in a key (GH-149233) Co-authored-by: Stan Ulbrych --- Lib/test/test_tomllib/test_misc.py | 13 +++++++++++++ Lib/tomllib/_parser.py | 11 +++++++++++ .../2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst | 1 + 3 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst diff --git a/Lib/test/test_tomllib/test_misc.py b/Lib/test/test_tomllib/test_misc.py index abd0842d10b254..af7ab91bba7cd1 100644 --- a/Lib/test/test_tomllib/test_misc.py +++ b/Lib/test/test_tomllib/test_misc.py @@ -119,6 +119,19 @@ def test_inline_table_recursion_limit(self): recursive_table_toml = nest_count * "key = {" + nest_count * "}" tomllib.loads(recursive_table_toml) + def test_key_recursion_limit(self): + nest_count = tomllib._parser.MAX_KEY_PARTS - 2 + nested_key_toml = "a." * nest_count + "a = 1" + tomllib.loads(nested_key_toml) + + nest_count = tomllib._parser.MAX_KEY_PARTS + 2 + nested_key_toml = "a." * nest_count + "a = 1" + with self.assertRaisesRegex( + RecursionError, + r"TOML key has more than the allowed [0-9]+ parts", + ): + tomllib.loads(nested_key_toml) + def test_types_import(self): """Test that `_types` module runs. diff --git a/Lib/tomllib/_parser.py b/Lib/tomllib/_parser.py index 8aa01301dcea32..b89934808008ef 100644 --- a/Lib/tomllib/_parser.py +++ b/Lib/tomllib/_parser.py @@ -29,6 +29,13 @@ from ._types import Key, ParseFloat, Pos +# Pathologically excessive number of parts in a key runs into quadratic +# behavior (e.g. in Flags.is_). +# Even if keys aren't currently parsed using recursion, they name a +# recursive structure, so it makes sense to limit it using getrecursionlimit() +# and RecursionError. +MAX_KEY_PARTS: Final = sys.getrecursionlimit() + ASCII_CTRL: Final = frozenset(chr(i) for i in range(32)) | frozenset(chr(127)) # Neither of these sets include quotation mark or backslash. They are @@ -470,6 +477,10 @@ def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]: pos = skip_chars(src, pos, TOML_WS) pos, key_part = parse_key_part(src, pos) key += (key_part,) + if len(key) > MAX_KEY_PARTS: + raise RecursionError( + f"TOML key has more than the allowed {MAX_KEY_PARTS} parts" + ) pos = skip_chars(src, pos, TOML_WS) diff --git a/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst b/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst new file mode 100644 index 00000000000000..c265b54db8bed4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-01-16-45-31.gh-issue-149231.x2nBEE.rst @@ -0,0 +1 @@ +In :mod:`tomllib`, the number of parts in TOML keys is now limited. From 7b7fa3f9bf3d7cdf3eb669d02b386e05b39c402a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 13:52:57 +0200 Subject: [PATCH 02/18] gh-148292: Update _ssl._SSLSocket for OpenSSL 4 (#149102) The _SSLSocket object now remembers if it gets an EOF error. In this case, read(), sendfile(), write() and do_handshake method calls fail with SSLEOFError without calling the underlying OpenSSL function. Co-authored-by: Gregory P. Smith --- Lib/test/test_ssl.py | 82 +++++++++++++++++++ ...-04-28-17-47-55.gh-issue-148292.oIq3ml.rst | 7 ++ Modules/_ssl.c | 47 +++++++++++ 3 files changed, 136 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 92ff5131a58e9d..97975db3bf49fb 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -2843,6 +2843,36 @@ def close(self): def stop(self): self.active = False +class TestEOFServer(threading.Thread): + def __init__(self): + super().__init__() + self.listening = threading.Event() + self.address = None + + def run(self): + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + context.load_cert_chain(CERTFILE) + server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + with server_sock: + server_sock.settimeout(support.SHORT_TIMEOUT) + server_sock.bind((HOST, 0)) + server_sock.listen(5) + + self.address = server_sock.getsockname() + self.listening.set() + + sock, addr = server_sock.accept() + sslconn = context.wrap_socket(sock, server_side=True) + with sslconn: + request = b'' + while chunk := sslconn.recv(1024): + request += chunk + if b'\n' in chunk: + break + + sslconn.sendall(b'server\n') + sslconn.shutdown(socket.SHUT_WR) + class AsyncoreEchoServer(threading.Thread): # this one's based on asyncore.dispatcher @@ -5001,6 +5031,58 @@ def background(sock): if cm.exc_value is not None: raise cm.exc_value + def test_got_eof(self): + # gh-148292: Test that _ssl._SSLSocket behaves the same on all OpenSSL + # versions on calling methods after EOF (after the first SSLEOFError). + + server = TestEOFServer() + server.start() + if not server.listening.wait(support.SHORT_TIMEOUT): + raise RuntimeError("server took too long") + self.addCleanup(server.join) + + context = ssl.create_default_context(cafile=CERTFILE) + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(support.SHORT_TIMEOUT) + sock.connect(server.address) + sslsock = context.wrap_socket(sock, server_hostname='localhost') + with sslsock: + sslsock.sendall(b'client\n') + # test the _ssl._SSLSocket object, not ssl.SSLSocket + sslobj = sslsock._sslobj + + data = sslobj.read(1024) + self.assertEqual(data, b'server\n') + + # The second read gets EOF error and sets got_eof_error to 1 + with self.assertRaises(ssl.SSLEOFError): + sslobj.read(1024) + + # Following read(), sendfile(), write() and do_handshake() calls + # must raise SSLEOFError + with self.assertRaises(ssl.SSLEOFError): + # The _SSLSocket remembers the previous EOF error + # and raises again SSLEOFError + sslobj.read(1024) + if hasattr(sslobj, 'sendfile'): + with open(__file__, "rb") as fp: + with self.assertRaises(ssl.SSLEOFError): + sslobj.sendfile(fp.fileno(), 0, 1) + with self.assertRaises(ssl.SSLEOFError): + sslobj.write(b'client2\n') + with self.assertRaises(ssl.SSLEOFError): + sslsock.do_handshake() + + self.assertEqual(sslsock.pending(), 0) + try: + sslsock.shutdown(socket.SHUT_WR) + except OSError as exc: + self.assertEqual(exc.errno, errno.ENOTCONN) + else: + # On Windows and on OpenSSL 1.1.1, shutdown() doesn't + # raise an error + pass + @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, "Test needs TLS 1.3 PHA") diff --git a/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst b/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst new file mode 100644 index 00000000000000..e1f308df5a678e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-28-17-47-55.gh-issue-148292.oIq3ml.rst @@ -0,0 +1,7 @@ +:mod:`ssl`: Update :class:`ssl.SSLSocket` and :class:`ssl.SSLObject` for +OpenSSL 4. The classes now remember if they get a :exc:`ssl.SSLEOFError`. In this +case, following :meth:`~ssl.SSLSocket.read`, :meth:`!sendfile`, +:meth:`~ssl.SSLSocket.write`, and :meth:`~ssl.SSLSocket.do_handshake` calls +raise :exc:`ssl.SSLEOFError` without calling the underlying OpenSSL function. +Thanks to that, :class:`ssl.SSLSocket` behaves the same on all OpenSSL versions +on EOF. Patch by Victor Stinner. diff --git a/Modules/_ssl.c b/Modules/_ssl.c index ea8a6d3fc1daca..3224ca7d0f93b9 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -377,6 +377,16 @@ typedef struct { enum py_ssl_server_or_client socket_type; PyObject *owner; /* weakref to Python level "owner" passed to servername callback */ PyObject *server_hostname; + // gh-148292: If non-zero, read(), sendfile(), write() and do_handshake() + // methods raise SSLEOFError without calling the underlying OpenSSL + // function. Set to 1 on PY_SSL_ERROR_EOF error. + // + // On OpenSSL 4, if SSL_read_ex() fails with + // SSL_R_UNEXPECTED_EOF_WHILE_READING, the following SSL_read_ex() call + // fails with a generic protocol error (ERR_peek_last_error() returns 0). + // Use got_eof_error to have the same behavior on OpenSSL 4 and newer and + // on OpenSSL 3 and older. + int got_eof_error; } PySSLSocket; #define PySSLSocket_CAST(op) ((PySSLSocket *)(op)) @@ -504,6 +514,10 @@ fill_and_set_sslerror(_sslmodulestate *state, PyObject *init_value, *msg, *key; PyUnicodeWriter *writer = NULL; + if (ssl_errno == PY_SSL_ERROR_EOF && sslsock != NULL) { + sslsock->got_eof_error = 1; + } + if (errcode != 0) { int lib, reason; @@ -649,6 +663,18 @@ fill_and_set_sslerror(_sslmodulestate *state, PyUnicodeWriter_Discard(writer); } + +static void +set_eof_error(PySSLSocket *sslsock) +{ + _sslmodulestate *state = get_state_sock(sslsock); + fill_and_set_sslerror(state, sslsock, state->PySSLEOFErrorObject, + PY_SSL_ERROR_EOF, + "EOF occurred in violation of protocol", + __LINE__, 0); +} + + // Set the appropriate SSL error exception. // err - error information from SSL and libc // exc - if not NULL, an exception from _debughelpers.c callback to be chained @@ -923,6 +949,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, self->shutdown_seen_zero = 0; self->owner = NULL; self->server_hostname = NULL; + self->got_eof_error = 0; /* Make sure the SSL error state is initialized */ ERR_clear_error(); @@ -1053,6 +1080,11 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) return NULL; } + if (self->got_eof_error) { + set_eof_error(self); + goto error; + } + timeout = GET_SOCKET_TIMEOUT(sock); has_timeout = (timeout > 0); if (has_timeout) { @@ -2638,6 +2670,11 @@ _ssl__SSLSocket_sendfile_impl(PySSLSocket *self, int fd, Py_off_t offset, return NULL; } + if (self->got_eof_error) { + set_eof_error(self); + goto error; + } + timeout = GET_SOCKET_TIMEOUT(sock); has_timeout = (timeout > 0); if (has_timeout) { @@ -2765,6 +2802,11 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b) return NULL; } + if (self->got_eof_error) { + set_eof_error(self); + goto error; + } + timeout = GET_SOCKET_TIMEOUT(sock); has_timeout = (timeout > 0); if (has_timeout) { @@ -2905,6 +2947,11 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, Py_ssize_t len, return NULL; } + if (self->got_eof_error) { + set_eof_error(self); + goto error; + } + if (!group_right_1) { if (len == 0) { Py_XDECREF(sock); From 1504bd671eebce0a99c15c113d219e0f344c03d9 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Mon, 4 May 2026 07:55:06 -0400 Subject: [PATCH 03/18] gh-149351: Avoid possible broken macOS framework install names when DESTDIR is specified during builds (#149352) --- Makefile.pre.in | 2 +- .../next/Build/2026-05-04-06-03-50.gh-issue-149351.hN4sF0.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Build/2026-05-04-06-03-50.gh-issue-149351.hN4sF0.rst diff --git a/Makefile.pre.in b/Makefile.pre.in index 3c166470b6c143..5789d33e7f4456 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1071,7 +1071,7 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \ $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION) $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \ -all_load $(LIBRARY) \ - -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/$(PYTHONFRAMEWORK) \ + -install_name $(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/$(PYTHONFRAMEWORK) \ -compatibility_version $(VERSION) \ -current_version $(VERSION) \ -framework CoreFoundation $(LIBS); diff --git a/Misc/NEWS.d/next/Build/2026-05-04-06-03-50.gh-issue-149351.hN4sF0.rst b/Misc/NEWS.d/next/Build/2026-05-04-06-03-50.gh-issue-149351.hN4sF0.rst new file mode 100644 index 00000000000000..792c8d394eccb2 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-05-04-06-03-50.gh-issue-149351.hN4sF0.rst @@ -0,0 +1,2 @@ +Avoid possible broken macOS framework install names when DESTDIR is +specified during builds. From 2ba0a81c9117ff5e4aa405b568f6dad62d409ab0 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 4 May 2026 15:14:57 +0300 Subject: [PATCH 04/18] gh-148352: Add more colour to `calendar` CLI output (#148354) Co-authored-by: Rihaan Meher --- Doc/library/calendar.rst | 5 ++ Doc/whatsnew/3.15.rst | 11 ++- Lib/_colorize.py | 12 +++ Lib/calendar.py | 81 ++++++++++++++----- Lib/test/test_calendar.py | 11 ++- ...-04-10-20-23-22.gh-issue-148352.lrec3W.rst | 1 + 6 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-10-20-23-22.gh-issue-148352.lrec3W.rst diff --git a/Doc/library/calendar.rst b/Doc/library/calendar.rst index 1c8f25e96dcd6c..3eb3f741eee45a 100644 --- a/Doc/library/calendar.rst +++ b/Doc/library/calendar.rst @@ -756,6 +756,11 @@ The following options are accepted: By default, today's date is highlighted in color and can be :ref:`controlled using environment variables `. +.. versionchanged:: next + By default, the month is now also highlighted in color, and + the days of the week are also in color. This behavior can be + :ref:`controlled using environment variables `. + *HTML-mode options:* .. option:: --css CSS, -c CSS diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 02a3a11e0564d9..2a493010ece0fd 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -832,14 +832,19 @@ binascii calendar -------- -* Calendar pages generated by the :class:`calendar.HTMLCalendar` class now support - dark mode and have been migrated to the HTML5 standard for improved accessibility. - (Contributed by Jiahao Li and Hugo van Kemenade in :gh:`137634`.) +* :mod:`calendar`'s :ref:`command-line ` text output has more + color. This can be controlled with :ref:`environment variables + `. + (Contributed by Hugo van Kemenade in :gh:`148352`.) * The :mod:`calendar`'s :ref:`command-line ` HTML output now accepts the year-month option: ``python -m calendar -t html 2009 06``. (Contributed by Pål Grønås Drange in :gh:`140212`.) +* Calendar pages generated by the :class:`calendar.HTMLCalendar` class now support + dark mode and have been migrated to the HTML5 standard for improved accessibility. + (Contributed by Jiahao Li and Hugo van Kemenade in :gh:`137634`.) + collections ----------- diff --git a/Lib/_colorize.py b/Lib/_colorize.py index 7c500e557f0180..5e0c0124e597b8 100644 --- a/Lib/_colorize.py +++ b/Lib/_colorize.py @@ -200,6 +200,14 @@ class Ast(ThemeSection): reset: str = ANSIColors.RESET +@dataclass(frozen=True, kw_only=True) +class Calendar(ThemeSection): + header: str = ANSIColors.BOLD + highlight: str = ANSIColors.BLACK + ANSIColors.BACKGROUND_YELLOW + weekday: str = ANSIColors.CYAN + reset: str = ANSIColors.RESET + + @dataclass(frozen=True, kw_only=True) class Difflib(ThemeSection): """A 'git diff'-like theme for `difflib.unified_diff`.""" @@ -459,6 +467,7 @@ class Theme: """ argparse: Argparse = field(default_factory=Argparse) ast: Ast = field(default_factory=Ast) + calendar: Calendar = field(default_factory=Calendar) difflib: Difflib = field(default_factory=Difflib) fancycompleter: FancyCompleter = field(default_factory=FancyCompleter) http_server: HttpServer = field(default_factory=HttpServer) @@ -476,6 +485,7 @@ def copy_with( *, argparse: Argparse | None = None, ast: Ast | None = None, + calendar: Calendar | None = None, difflib: Difflib | None = None, fancycompleter: FancyCompleter | None = None, http_server: HttpServer | None = None, @@ -496,6 +506,7 @@ def copy_with( return type(self)( argparse=argparse or self.argparse, ast=ast or self.ast, + calendar=calendar or self.calendar, difflib=difflib or self.difflib, fancycompleter=fancycompleter or self.fancycompleter, http_server=http_server or self.http_server, @@ -520,6 +531,7 @@ def no_colors(cls) -> Self: return cls( argparse=Argparse.no_colors(), ast=Ast.no_colors(), + calendar=Calendar.no_colors(), difflib=Difflib.no_colors(), fancycompleter=FancyCompleter.no_colors(), http_server=HttpServer.no_colors(), diff --git a/Lib/calendar.py b/Lib/calendar.py index d80c3fd9524776..fa9775ab040b14 100644 --- a/Lib/calendar.py +++ b/Lib/calendar.py @@ -686,28 +686,61 @@ def __init__(self, highlight_day=None, *args, **kwargs): super().__init__(*args, **kwargs) self.highlight_day = highlight_day - def formatweek(self, theweek, width, *, highlight_day=None): + def _get_theme(self): + from _colorize import get_theme + + return get_theme(tty_file=sys.stdout) + + def formatday(self, day, weekday, width, *, highlight_day=None): """ - Returns a single week in a string (no newline). + Returns a formatted day. """ - if highlight_day: - from _colorize import get_colors - - ansi = get_colors() - highlight = f"{ansi.BLACK}{ansi.BACKGROUND_YELLOW}" - reset = ansi.RESET + if day == 0: + s = '' else: - highlight = reset = "" + s = f'{day:2}' + s = s.center(width) + if day == highlight_day: + theme = self._get_theme().calendar + s = f"{theme.highlight}{s}{theme.reset}" + return s + def formatweek(self, theweek, width, *, highlight_day=None): + """ + Returns a single week in a string (no newline). + """ return ' '.join( - ( - f"{highlight}{self.formatday(d, wd, width)}{reset}" - if d == highlight_day - else self.formatday(d, wd, width) - ) + self.formatday(d, wd, width, highlight_day=highlight_day) for (d, wd) in theweek ) + def formatweekheader(self, width): + """ + Return a header for a week. + """ + header = super().formatweekheader(width) + theme = self._get_theme().calendar + return f"{theme.weekday}{header}{theme.reset}" + + def formatmonthname(self, theyear, themonth, width, withyear=True): + """ + Return a formatted month name. + """ + name = super().formatmonthname(theyear, themonth, width, withyear) + theme = self._get_theme().calendar + if ( + self.highlight_day + and self.highlight_day.year == theyear + and self.highlight_day.month == themonth + ): + color = theme.highlight + name_only = name.strip() + colored_name = f"{color}{name_only}{theme.reset}" + return name.replace(name_only, colored_name, 1) + else: + color = theme.header + return f"{color}{name}{theme.reset}" + def formatmonth(self, theyear, themonth, w=0, l=0): """ Return a month's calendar string (multi-line). @@ -742,7 +775,9 @@ def formatyear(self, theyear, w=2, l=1, c=6, m=3): colwidth = (w + 1) * 7 - 1 v = [] a = v.append - a(repr(theyear).center(colwidth*m+c*(m-1)).rstrip()) + theme = self._get_theme().calendar + year = repr(theyear).center(colwidth*m+c*(m-1)).rstrip() + a(f"{theme.header}{year}{theme.reset}") a('\n'*l) header = self.formatweekheader(w) for (i, row) in enumerate(self.yeardays2calendar(theyear, m)): @@ -843,28 +878,30 @@ def timegm(tuple): def main(args=None): import argparse - parser = argparse.ArgumentParser(color=True) + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) textgroup = parser.add_argument_group('text only arguments') htmlgroup = parser.add_argument_group('html only arguments') textgroup.add_argument( "-w", "--width", type=int, default=2, - help="width of date column (default 2)" + help="width of date column" ) textgroup.add_argument( "-l", "--lines", type=int, default=1, - help="number of lines for each week (default 1)" + help="number of lines for each week" ) textgroup.add_argument( "-s", "--spacing", type=int, default=6, - help="spacing between months (default 6)" + help="spacing between months" ) textgroup.add_argument( "-m", "--months", type=int, default=3, - help="months per row (default 3)" + help="months per row" ) htmlgroup.add_argument( "-c", "--css", @@ -879,7 +916,7 @@ def main(args=None): parser.add_argument( "-e", "--encoding", default=None, - help="encoding to use for output (default utf-8)" + help="encoding to use for output" ) parser.add_argument( "-t", "--type", @@ -890,7 +927,7 @@ def main(args=None): parser.add_argument( "-f", "--first-weekday", type=int, default=0, - help="weekday (0 is Monday, 6 is Sunday) to start each week (default 0)" + help="weekday (0 is Monday, 6 is Sunday) to start each week" ) parser.add_argument( "year", diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py index 79f0ebb78ffe9c..6ed27b4095bc1d 100644 --- a/Lib/test/test_calendar.py +++ b/Lib/test/test_calendar.py @@ -1068,6 +1068,7 @@ def test_several_leapyears_in_range(self): def conv(s): return s.replace('\n', os.linesep).encode() +@support.force_not_colorized_test_class class CommandLineTestCase(unittest.TestCase): def setUp(self): self.runners = [self.run_cli_ok, self.run_cmd_ok] @@ -1121,7 +1122,6 @@ def assertFailure(self, *args): self.assertCLIFails(*args) self.assertCmdFails(*args) - @support.force_not_colorized def test_help(self): stdout = self.run_cmd_ok('-h') self.assertIn(b'usage:', stdout) @@ -1256,6 +1256,15 @@ def test_html_output_year_css(self): self.assertIn(b'', output) +@support.force_colorized_test_class +class ColorTestCase(unittest.TestCase): + def test_formatmonth_color(self): + today = datetime.date(2026, 5, 4) + cal = calendar._CLIDemoCalendar(highlight_day=today) + output = cal.formatmonth(2026, 5) + self.assertIn("\x1b[30m\x1b[43mMay 2026\x1b[0m\n\x1b[36m", output) + + class MiscTestCase(unittest.TestCase): def test__all__(self): not_exported = { diff --git a/Misc/NEWS.d/next/Library/2026-04-10-20-23-22.gh-issue-148352.lrec3W.rst b/Misc/NEWS.d/next/Library/2026-04-10-20-23-22.gh-issue-148352.lrec3W.rst new file mode 100644 index 00000000000000..508b36791ea0e2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-04-10-20-23-22.gh-issue-148352.lrec3W.rst @@ -0,0 +1 @@ +Add more color to :mod:`calendar`'s CLI output. Patch by Hugo van Kemenade. From 7aedd0a6c6ae3b5cdd601e84411e41c56f8d00b9 Mon Sep 17 00:00:00 2001 From: wouter bolsterlee Date: Mon, 4 May 2026 15:03:20 +0200 Subject: [PATCH 05/18] gh-87245: Improve IPv6Address.ipv4_mapped documentation (#92572) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid the phrasing ‘starting with ::FFFF/96’, which is confusing since it seems to mix a prefix and a range. Instead, make it clear what the actual range is, and refer to the relevant RFC. Closes #87245. --- Doc/library/ipaddress.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst index ba20310d63b277..9ccd8602bcb2c3 100644 --- a/Doc/library/ipaddress.rst +++ b/Doc/library/ipaddress.rst @@ -367,9 +367,9 @@ write code that handles both IP versions correctly. Address objects are .. attribute:: ipv4_mapped - For addresses that appear to be IPv4 mapped addresses (starting with - ``::FFFF/96``), this property will report the embedded IPv4 address. - For any other address, this property will be ``None``. + For addresses that appear to be IPv4 mapped addresses in the range + ``::FFFF:0:0/96`` as defined by :RFC:`4291`, this property reports the + embedded IPv4 address. For any other address, this property will be ``None``. .. attribute:: scope_id From fc9602819181d68568259029a2accfd2dfcd086d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 15:21:04 +0200 Subject: [PATCH 06/18] gh-148600: Add OpenSSL 4.0.0 support to test configurations (#149356) Co-authored-by: Charlie Lin --- .github/workflows/build.yml | 1 + Lib/test/test_poplib.py | 4 +++- .../next/Tests/2026-04-21-12-33-14.gh-issue-148600.vnTb3t.rst | 1 + Tools/ssl/multissltests.py | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Tests/2026-04-21-12-33-14.gh-issue-148600.vnTb3t.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4397fc7de54a4..1af3a0607f9ad2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -283,6 +283,7 @@ jobs: - { name: openssl, version: 3.4.5 } - { name: openssl, version: 3.5.6 } - { name: openssl, version: 3.6.2 } + - { name: openssl, version: 4.0.0 } ## AWS-LC - { name: aws-lc, version: 1.72.1 } env: diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py index 18ca7cb556836e..f08b945c8f57e5 100644 --- a/Lib/test/test_poplib.py +++ b/Lib/test/test_poplib.py @@ -185,7 +185,8 @@ def _do_tls_handshake(self): elif err.args[0] == ssl.SSL_ERROR_EOF: return self.handle_close() # TODO: SSLError does not expose alert information - elif ("SSLV3_ALERT_BAD_CERTIFICATE" in err.args[1] or + elif ("TLS_ALERT_BAD_CERTIFICATE" in err.args[1] or + "SSLV3_ALERT_BAD_CERTIFICATE" in err.args[1] or "SSLV3_ALERT_CERTIFICATE_UNKNOWN" in err.args[1]): return self.handle_close() raise @@ -423,6 +424,7 @@ def test_stls_context(self): self.assertEqual(ctx.check_hostname, True) with self.assertRaises(ssl.CertificateError): resp = self.client.stls(context=ctx) + self.client = poplib.POP3("localhost", self.server.port, timeout=test_support.LOOPBACK_TIMEOUT) resp = self.client.stls(context=ctx) diff --git a/Misc/NEWS.d/next/Tests/2026-04-21-12-33-14.gh-issue-148600.vnTb3t.rst b/Misc/NEWS.d/next/Tests/2026-04-21-12-33-14.gh-issue-148600.vnTb3t.rst new file mode 100644 index 00000000000000..a7d4c0cc80a146 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-04-21-12-33-14.gh-issue-148600.vnTb3t.rst @@ -0,0 +1 @@ +Add OpenSSL 4.0.0 support to test configurations. diff --git a/Tools/ssl/multissltests.py b/Tools/ssl/multissltests.py index 6be1a5ae94ebc6..ad3e4b6596ed7a 100755 --- a/Tools/ssl/multissltests.py +++ b/Tools/ssl/multissltests.py @@ -54,6 +54,7 @@ "3.4.5", "3.5.6", "3.6.2", + "4.0.0", # See make_ssl_data.py for notes on adding a new version. ] From ce51c1881889b6ed9f806d2f3c6551cb03c515da Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 15:37:45 +0200 Subject: [PATCH 07/18] gh-146063: Add PyObject_CallFinalizerFromDealloc() to the limited C API (#146172) Co-authored-by: Petr Viktorin --- Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.15.rst | 4 ++++ Include/cpython/object.h | 1 - Include/object.h | 1 + Lib/test/test_stable_abi_ctypes.py | 1 + .../next/C_API/2026-03-19-15-28-14.gh-issue-146063.Sc-1RU.rst | 2 ++ Misc/stable_abi.toml | 4 +++- PC/python3dll.c | 1 + 8 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-03-19-15-28-14.gh-issue-146063.Sc-1RU.rst diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 4ae5e999f0bf21..2ef2bccf2b7728 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -565,6 +565,7 @@ func,PyObject_ASCII,3.2,, func,PyObject_AsFileDescriptor,3.2,, func,PyObject_Bytes,3.2,, func,PyObject_Call,3.2,, +func,PyObject_CallFinalizerFromDealloc,3.15,, func,PyObject_CallFunction,3.2,, func,PyObject_CallFunctionObjArgs,3.2,, func,PyObject_CallMethod,3.2,, diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 2a493010ece0fd..a8a779fefa0c85 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -2050,6 +2050,10 @@ New features (Contributed by Victor Stinner in :gh:`141510`.) +* Add :c:func:`PyObject_CallFinalizerFromDealloc` function to the limited C + API. + (Contributed by Victor Stinner in :gh:`146063`.) + * Add :c:func:`PySys_GetAttr`, :c:func:`PySys_GetAttrString`, :c:func:`PySys_GetOptionalAttr`, and :c:func:`PySys_GetOptionalAttrString` functions as replacements for :c:func:`PySys_GetObject`. diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 0b50d2a9dd8698..d0b3d0cb14de3d 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -307,7 +307,6 @@ Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Id PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *); -PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); PyAPI_FUNC(void) PyUnstable_Object_ClearWeakRefsNoCallbacks(PyObject *); diff --git a/Include/object.h b/Include/object.h index d51132be1a6656..043be0260b1aec 100644 --- a/Include/object.h +++ b/Include/object.h @@ -782,6 +782,7 @@ PyAPI_FUNC(int) PyType_Freeze(PyTypeObject *type); #endif #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15) +PyAPI_FUNC(int) PyObject_CallFinalizerFromDealloc(PyObject *); PyAPI_FUNC(PyObject *) PyType_GetModuleByToken(PyTypeObject *type, const void *token); PyAPI_FUNC(void *) PyObject_GetTypeData_DuringGC(PyObject *obj, diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index ed0868e0017fce..5dae5dfccac5d3 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -552,6 +552,7 @@ def test_windows_feature_macros(self): "PyObject_AsWriteBuffer", "PyObject_Bytes", "PyObject_Call", + "PyObject_CallFinalizerFromDealloc", "PyObject_CallFunction", "PyObject_CallFunctionObjArgs", "PyObject_CallMethod", diff --git a/Misc/NEWS.d/next/C_API/2026-03-19-15-28-14.gh-issue-146063.Sc-1RU.rst b/Misc/NEWS.d/next/C_API/2026-03-19-15-28-14.gh-issue-146063.Sc-1RU.rst new file mode 100644 index 00000000000000..e20e11a754f694 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-03-19-15-28-14.gh-issue-146063.Sc-1RU.rst @@ -0,0 +1,2 @@ +Add :c:func:`PyObject_CallFinalizerFromDealloc` function to the limited C API. +Patch by Victor Stinner. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 101737a27829c9..e6c63227d20446 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2691,7 +2691,6 @@ added = '3.15' # PEP 757 import/export API. - [function.PyLong_GetNativeLayout] added = '3.15' [function.PyLong_Export] @@ -2715,3 +2714,6 @@ # Note: The `_reserved` member of this struct is for interal use only. # (The definition of 'full-abi' was clarified when this entry was added.) struct_abi_kind = 'full-abi' + +[function.PyObject_CallFinalizerFromDealloc] + added = '3.15' diff --git a/PC/python3dll.c b/PC/python3dll.c index abbe35c342c13e..6b9ef0a4164c16 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -489,6 +489,7 @@ EXPORT_FUNC(PyObject_AsReadBuffer) EXPORT_FUNC(PyObject_AsWriteBuffer) EXPORT_FUNC(PyObject_Bytes) EXPORT_FUNC(PyObject_Call) +EXPORT_FUNC(PyObject_CallFinalizerFromDealloc) EXPORT_FUNC(PyObject_CallFunction) EXPORT_FUNC(PyObject_CallFunctionObjArgs) EXPORT_FUNC(PyObject_CallMethod) From c3972f2795bf9270008d09dc6919b9735e20c606 Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Mon, 4 May 2026 21:42:02 +0800 Subject: [PATCH 08/18] gh-148418: Fix a possible reference leak in a corrupted TYPE_CODE marshal stream (GH-148419) --- .../2026-04-12-10-40-57.gh-issue-148418.ggA1LZ.rst | 1 + Python/marshal.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-12-10-40-57.gh-issue-148418.ggA1LZ.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-12-10-40-57.gh-issue-148418.ggA1LZ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-12-10-40-57.gh-issue-148418.ggA1LZ.rst new file mode 100644 index 00000000000000..793858be7814c1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-12-10-40-57.gh-issue-148418.ggA1LZ.rst @@ -0,0 +1 @@ +Fix a possible reference leak in a corrupted ``TYPE_CODE`` marshal stream. diff --git a/Python/marshal.c b/Python/marshal.c index dace22da0d4a94..990afefe0d3b41 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -1636,7 +1636,7 @@ r_object(RFILE *p) goto code_error; firstlineno = (int)r_long(p); if (firstlineno == -1 && PyErr_Occurred()) - break; + goto code_error; linetable = r_object(p); if (linetable == NULL) goto code_error; From 5235467b9183a8be8675aed17bd5b5a993975da7 Mon Sep 17 00:00:00 2001 From: Alyssa Coghlan Date: Mon, 4 May 2026 20:42:20 +0700 Subject: [PATCH 09/18] gh-149010: Improve reliability of inspect CLI (#149357) * Handle non-source modules more gracefully (and consistently) * Improve handling of frozen modules (which may or may not have source) * Avoid reporting misleading info when looking up objects via aliases * Refactor CLI implementation to improve testability * Add several more test cases Closes #149010 --- Doc/library/inspect.rst | 9 +- Lib/inspect.py | 120 +++++++-- Lib/test/test_inspect/test_inspect.py | 237 ++++++++++++++++-- ...-05-04-00-51-32.gh-issue-149010.BCp_8k.rst | 6 + 4 files changed, 334 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-04-00-51-32.gh-issue-149010.BCp_8k.rst diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index e23449886a38f1..4825ac11ae2ee3 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -1833,8 +1833,15 @@ from the command line. By default, accepts the name of a module and prints the source of that module. A class or function within the module can be printed instead by -appended a colon and the qualified name of the target object. +appending a colon and the qualified name of the target object. .. option:: --details Print information about the specified object rather than the source code + +.. versionchanged:: next + + The ``--details`` option now supports basic introspection for modules + without available source code and indicates when modules are frozen. + It also indicates when the given target reference is not the canonical + name of the referenced object. diff --git a/Lib/inspect.py b/Lib/inspect.py index d3af61b26e280a..af304f186a69bc 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3351,6 +3351,95 @@ class BufferFlags(enum.IntFlag): WRITE = 0x200 +def _get_details_for_cli(module, nominal_target, resolved_target): + # Determine if the given module name is an alias for another module, + # or if it is reexporting a name that is actually defined elsewhere + resolved_module = getmodule(resolved_target) + if resolved_module is not None and resolved_module is not module: + # Referenced target indicates it was defined somewhere else, + # so report the details of that module rather than the lookup module + module = resolved_module + reported_module_name = module.__name__ + # Ensure the reported source file reflects the actual defining location + try: + source_file = getsourcefile(resolved_target) + except Exception: + try: + source_file = getsourcefile(module) + except Exception: + source_file = None + # Determine if the nominal target location is its defining location + if resolved_target is module: + reported_target = reported_module_name + else: + reported_qualname = getattr(resolved_target, "__qualname__", None) + if not reported_qualname: + reported_qualname = nominal_target.partition(":")[2] + reported_target = f"{reported_module_name}:{reported_qualname}" + # Special case for looking up functions in frozen modules + if source_file == f"": + source_file = module.__file__ + # Populate the actual details to be reported + details = { + "target": reported_target, + "origin": module.__spec__.origin, + "cached": module.__spec__.cached, + "source": source_file, + } + if reported_target != nominal_target: + details["alias"] = nominal_target + error = None + if not source_file: + if module.__name__ in sys.builtin_module_names: + error = "No source code available for builtin module" + else: + error = "No source code available for defining module" + if resolved_target is module: + details["loader"] = repr(module.__spec__.loader) + if hasattr(module, '__path__'): + details["submodule_paths"] = str(module.__path__) + elif source_file: + try: + __, lineno = findsource(resolved_target) + except Exception: + error = "Failed to retrieve source code for given target" + else: + details["lineno"] = lineno + if error: + details["error"] = error + return details + +def _render_details_for_cli(details): + resolved_target = details["target"] + alias = details.get("alias") + if alias: + rendered_target = f'{resolved_target} (looked up as "{alias}")' + else: + rendered_target = resolved_target + lines = [ + f'Target: {rendered_target}', + f'Origin: {details["origin"]}', + f'Source: {details["source"]}', + f'Cached: {details["cached"]}', + ] + loader = details.get("loader") + if loader: + lines.append(f'Loader: {loader}') + submodule_paths = details.get("submodule_paths") + if submodule_paths: + lines.append(f'Submodule search paths: {submodule_paths}') + else: + error = details.get("error") + if error: + # The error is only informational when retrieving object details + lines.append(error) + else: + lines.append(f'Line: {details["lineno"]}') + + lines.append("") + return "\n".join(lines) + + def _main(): """ Logic for inspecting an object given at command line """ import argparse @@ -3367,6 +3456,8 @@ def _main(): args = parser.parse_args() + # We don't use `pkgutil.resolve_name` here because we want to obtain + # references to both the module *and* the fully resolved target object target = args.object mod_name, has_attrs, attrs = target.partition(":") try: @@ -3384,29 +3475,16 @@ def _main(): for part in parts: obj = getattr(obj, part) - if module.__name__ in sys.builtin_module_names: - print("Can't get info for builtin modules.", file=sys.stderr) - sys.exit(1) - + details = _get_details_for_cli(module, target, obj) if args.details: - print(f'Target: {target}') - print(f'Origin: {getsourcefile(module)}') - print(f'Cached: {module.__spec__.cached}') - if obj is module: - print(f'Loader: {module.__loader__!r}') - if hasattr(module, '__path__'): - print(f'Submodule search path: {module.__path__}') - else: - try: - __, lineno = findsource(obj) - except Exception: - pass - else: - print(f'Line: {lineno}') - - print() + print(_render_details_for_cli(details)) else: - print(getsource(obj)) + # Attempt to render target source details + error = details.get("error") + if error: + sys.exit(error) + else: + print(getsource(obj)) if __name__ == "__main__": diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 68ea62f565d824..efe9d27e3407ff 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6493,8 +6493,19 @@ def test_wrapped_descriptor(self): self.assertIs(inspect.unwrap(staticmethod(classmethod)), classmethod) self.assertIs(inspect.unwrap(classmethod(staticmethod)), staticmethod) +def _clean_object_ids(text): + # Helper to handle "" details in CLI output checks + import re + detect = r"object at 0x([0-9A-Fa-f]+)>" + replace = "object at 0x...>" + return re.sub(detect, replace, text) + +class TestModuleCLI(unittest.TestCase): + + BUILTIN_ERROR = "No source code available for builtin module" + NO_SOURCE_ERROR = "No source code available for defining module" + NO_SOURCE_TARGET_ERROR = "Failed to retrieve source code for given target" -class TestMain(unittest.TestCase): def test_only_source(self): module = importlib.import_module('unittest') rc, out, err = assert_python_ok('-m', 'inspect', @@ -6522,27 +6533,223 @@ def test_qualname_source(self): inspect.getsource(ThreadPoolExecutor).splitlines()) self.assertEqual(err, b'') - def test_builtins(self): + def test_error_builtins(self): _, out, err = assert_python_failure('-m', 'inspect', 'sys') lines = err.decode().splitlines() - self.assertEqual(lines, ["Can't get info for builtin modules."]) + self.assertEqual(lines, [self.BUILTIN_ERROR]) + + def test_error_extension(self): + module_name = "_testcapi" + if module_name in sys.builtin_module_names: + # WASI test environment has even _testcapi as a builtin module + expected_error = self.BUILTIN_ERROR + else: + expected_error = self.NO_SOURCE_ERROR + _, out, err = assert_python_failure('-m', 'inspect', + module_name) + lines = err.decode().splitlines() + self.assertEqual(lines, [expected_error]) + + def test_error_data(self): + _, out, err = assert_python_failure('-m', 'inspect', + 'importlib.machinery:SOURCE_SUFFIXES') + lines = err.decode().splitlines() + self.assertEqual(lines, [self.NO_SOURCE_TARGET_ERROR]) + + def test_details_option_with_package(self): + module_name = 'unittest' + module = importlib.import_module(module_name) + args = support.optim_args_from_interpreter_flags() + rc, out, err = assert_python_ok(*args, '-m', 'inspect', + module_name, '--details') + # Full rendering check on the expected output + expected_lines = [ + f"Target: {module.__name__}", # No aliasing + f"Origin: {module.__spec__.origin}", + f"Source: {module.__file__}", + f"Cached: {module.__spec__.cached}", # None is still displayed + f"Loader: {_clean_object_ids(repr(module.__spec__.loader))}", + f"Submodule search paths: {module.__path__}", + "", + ] + output_lines = _clean_object_ids(out.decode()).splitlines() + self.assertEqual(output_lines, expected_lines) + self.assertEqual(err, b'') + + def test_details_option_with_builtin_module(self): + # Also an end-to-end test of non-package lookups + module_name = 'sys' + module = importlib.import_module(module_name) + args = support.optim_args_from_interpreter_flags() + rc, out, err = assert_python_ok(*args, '-m', 'inspect', + module_name, '--details') + # Full rendering check on the expected output + # No error is reported when just fetching the module details + expected_lines = [ + f"Target: {module.__name__}", # No aliasing + f"Origin: {module.__spec__.origin}", + "Source: None", + "Cached: None", + f"Loader: {_clean_object_ids(repr(module.__spec__.loader))}", + "", + ] + output_lines = _clean_object_ids(out.decode()).splitlines() + self.assertEqual(output_lines, expected_lines) + self.assertEqual(err, b'') + + def test_details_option_with_data_target(self): + # Also an end-to-end test of non-module lookups without aliasing + module_name = 'importlib.machinery' + cli_target = f"{module_name}:SOURCE_SUFFIXES" + module = importlib.import_module(module_name) + args = support.optim_args_from_interpreter_flags() + rc, out, err = assert_python_ok(*args, '-m', 'inspect', + cli_target, '--details') + # Full rendering check on the expected output + # The error is only informational when reading source details + expected_lines = [ + f"Target: {cli_target}", # No aliasing + f"Origin: {module.__spec__.origin}", + f"Source: {module.__file__}", + f"Cached: {module.__spec__.cached}", # None is still displayed + self.NO_SOURCE_TARGET_ERROR, + "", + ] + output_lines = out.decode().splitlines() + self.assertEqual(output_lines, expected_lines) + self.assertEqual(err, b'') + + @unittest.skipIf(not os.path.exists(os.path.__file__), "Needs frozen source file") + def test_details_option_with_aliased_target(self): + # Also an end-to-end test of successful non-module lookups + module = importlib.import_module("os.path") + target = module.join + cli_target = "os:path.join" # Defining module is os.path, not os + defining_target = f"{target.__module__}:{target.__qualname__}" - def test_details(self): - module = importlib.import_module('unittest') args = support.optim_args_from_interpreter_flags() rc, out, err = assert_python_ok(*args, '-m', 'inspect', - 'unittest', '--details') - output = out.decode() - # Just a quick safety check on the output - self.assertIn(module.__spec__.name, output) - self.assertIn(module.__name__, output) - self.assertIn(module.__spec__.origin, output) - self.assertIn(module.__file__, output) - if module.__spec__.cached: - self.assertIn(module.__spec__.cached, output) + cli_target, '--details') + # Full rendering check on the expected output + expected_lines = [ + f'Target: {defining_target} (looked up as "{cli_target}")', + f"Origin: {module.__spec__.origin}", + f"Source: {module.__file__}", + f"Cached: {module.__spec__.cached}", # None is still displayed + f"Line: {inspect.findsource(target)[1]}", + "", + ] + output_lines = out.decode().splitlines() + self.assertEqual(output_lines, expected_lines) self.assertEqual(err, b'') + def _check_details(self, module, details, other_expected_keys=(), *, alias=None, error=None): + expected_keys = {"target", "origin", "source", "cached"} + if other_expected_keys: + expected_keys |= other_expected_keys + if alias is not None: + expected_keys.add("alias") + if error is not None: + expected_keys.add("error") + self.assertEqual(set(details.keys()), expected_keys) + self.assertEqual(module.__spec__.origin, details["origin"]) + try: + expected_source = inspect.getsourcefile(module) + except Exception: + expected_source = None + if expected_source and expected_source.startswith(" Date: Mon, 4 May 2026 15:45:31 +0200 Subject: [PATCH 10/18] gh-147998: Fix possible memory leak in _pop_preserved (crossinterp.c) (GH-147999) --- .../2026-04-02-13-25-09.gh-issue-147998.wnzkRT.rst | 3 +++ Python/crossinterp.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-04-02-13-25-09.gh-issue-147998.wnzkRT.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-02-13-25-09.gh-issue-147998.wnzkRT.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-02-13-25-09.gh-issue-147998.wnzkRT.rst new file mode 100644 index 00000000000000..e83d9929eae5e0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-02-13-25-09.gh-issue-147998.wnzkRT.rst @@ -0,0 +1,3 @@ +Fixed a memory leak in interpreter helper calls so cleanup works when an +operation falls across interpreter boundaries. Patch by Maurycy +Pawłowski-Wieroński. diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 4cd4b32ef906bb..6b489bf03f86ec 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -3006,7 +3006,7 @@ _pop_preserved(_PyXI_session *session, *p_xidata = NULL; } else { - _PyXI_namespace *xidata = _create_sharedns(session->_preserved); + xidata = _create_sharedns(session->_preserved); if (xidata == NULL) { failure.code = _PyXI_ERR_PRESERVE_FAILURE; goto error; From 6e6f9053e368a8c8b05872743f9ac04c49418d7e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 16:14:23 +0200 Subject: [PATCH 11/18] gh-148675: Add Zd/Zf formats to array, ctypes, memoryview, struct (#148676) * Add Zd/Zf format support to array, memoryview and struct. * ctypes: Replace F/D/G complex format with Zf/Zd/Zg. * Modify array, ctypes and struct modules to support format strings longer than 1 character (such as "Zd"). * Change array.typecodes type from str to tuple. --- Doc/library/array.rst | 11 +- Doc/library/ctypes.rst | 10 +- Doc/library/struct.rst | 9 +- Doc/whatsnew/3.15.rst | 20 +- Lib/ctypes/__init__.py | 6 +- Lib/test/test_array.py | 35 ++- Lib/test/test_buffer.py | 40 +++- .../test_ctypes/test_c_simple_type_meta.py | 8 +- Lib/test/test_ctypes/test_numbers.py | 13 +- Lib/test/test_memoryview.py | 6 +- Lib/test/test_struct.py | 6 +- ...-04-17-13-56-44.gh-issue-148675.f1kG70.rst | 2 + ...-05-02-12-30-35.gh-issue-148675.cu2YFT.rst | 3 + ...-05-02-15-58-08.gh-issue-148675.b3ZNlj.rst | 4 + Modules/_ctypes/_ctypes.c | 85 ++++---- Modules/_ctypes/callproc.c | 6 +- Modules/_ctypes/cfield.c | 127 ++++++----- Modules/_ctypes/ctypes.h | 5 +- Modules/_struct.c | 204 ++++++++++-------- Modules/arraymodule.c | 202 ++++++++++------- Modules/clinic/arraymodule.c.h | 21 +- Objects/memoryobject.c | 136 ++++++++++-- 22 files changed, 625 insertions(+), 334 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-04-17-13-56-44.gh-issue-148675.f1kG70.rst create mode 100644 Misc/NEWS.d/next/Library/2026-05-02-12-30-35.gh-issue-148675.cu2YFT.rst create mode 100644 Misc/NEWS.d/next/Library/2026-05-02-15-58-08.gh-issue-148675.b3ZNlj.rst diff --git a/Doc/library/array.rst b/Doc/library/array.rst index 4468edb6efa654..3cd107460596d1 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -52,6 +52,10 @@ defined: +-----------+--------------------+-------------------+-----------------------+-------+ | ``'D'`` | double complex | complex | 16 | \(4) | +-----------+--------------------+-------------------+-----------------------+-------+ +| ``'Zf'`` | float complex | complex | 8 | \(4) | ++-----------+--------------------+-------------------+-----------------------+-------+ +| ``'Zd'`` | double complex | complex | 16 | \(4) | ++-----------+--------------------+-------------------+-----------------------+-------+ Notes: @@ -80,7 +84,7 @@ Notes: .. versionadded:: 3.15 (4) - Complex types (``F`` and ``D``) are available unconditionally, + Complex types (``F``, ``D``, ``Zf`` and ``Zd``) are available unconditionally, regardless on support for complex types (the Annex G of the C11 standard) by the C compiler. As specified in the C11 standard, each complex type is represented by a @@ -105,7 +109,10 @@ The module defines the following item: .. data:: typecodes - A string with all available type codes. + A tuple with all available type codes. + + .. versionchanged:: next + The type changed from :class:`str` to :class:`tuple`. The module defines the following type: diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index b8d615565a590c..3db66ad8ea66e7 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -370,15 +370,19 @@ in both C and ``libffi``, the following complex types are available: * - :class:`c_float_complex` - :c:expr:`float complex` - :py:class:`complex` - - ``'F'`` + - ``'Zf'`` * - :class:`c_double_complex` - :c:expr:`double complex` - :py:class:`complex` - - ``'D'`` + - ``'Zd'`` * - :class:`c_longdouble_complex` - :c:expr:`long double complex` - :py:class:`complex` - - ``'G'`` + - ``'Zg'`` + +.. versionchanged:: next + The :py:attr:`~_SimpleCData._type_` types ``F``, ``D`` and ``G`` have been + replaced with ``Zf``, ``Zd`` and ``Zg``. All these types can be created by calling them with an optional initializer of diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index f504f931f0fa20..bf5f754e156d3c 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -264,6 +264,10 @@ platform-dependent. +--------+--------------------------+--------------------+----------------+------------+ | ``D`` | :c:expr:`double complex` | complex | 16 | \(10) | +--------+--------------------------+--------------------+----------------+------------+ +| ``Zf`` | :c:expr:`float complex` | complex | 8 | \(10) | ++--------+--------------------------+--------------------+----------------+------------+ +| ``Zd`` | :c:expr:`double complex` | complex | 16 | \(10) | ++--------+--------------------------+--------------------+----------------+------------+ | ``s`` | :c:expr:`char[]` | bytes | | \(9) | +--------+--------------------------+--------------------+----------------+------------+ | ``p`` | :c:expr:`char[]` | bytes | | \(8) | @@ -280,6 +284,9 @@ platform-dependent. .. versionchanged:: 3.14 Added support for the ``'F'`` and ``'D'`` formats. +.. versionchanged:: next + Added support for the ``'Zf'`` and ``'Zd'`` formats. + .. seealso:: The :mod:`array` and :ref:`ctypes ` modules, @@ -372,7 +379,7 @@ Notes: For the ``'F'`` and ``'D'`` format characters, the packed representation uses the IEEE 754 binary32 and binary64 format for components of the complex number, regardless of the floating-point format used by the platform. - Note that complex types (``F`` and ``D``) are available unconditionally, + Note that complex types (``F``/``Zf`` and ``D``/``Zd``) are available unconditionally, despite complex types being an optional feature in C. As specified in the C11 standard, each complex type is represented by a two-element C array containing, respectively, the real and imaginary parts. diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index a8a779fefa0c85..2e408f258e2805 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -671,9 +671,9 @@ Other language changes (Contributed by James Hilton-Balfe in :gh:`128335`.) * The class :class:`memoryview` now supports the :c:expr:`float complex` and - :c:expr:`double complex` C types: formatting characters ``'F'`` and ``'D'`` - respectively. - (Contributed by Sergey B Kirpichev in :gh:`146151`.) + :c:expr:`double complex` C types: formatting characters ``'F'``/``'Zf'`` + and ``'D'``/``'Zd'`` respectively. + (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Allow the *count* argument of :meth:`bytes.replace` to be a keyword. (Contributed by Stan Ulbrych in :gh:`147856`.) @@ -724,13 +724,17 @@ array ----- * Support the :c:expr:`float complex` and :c:expr:`double complex` C types: - formatting characters ``'F'`` and ``'D'`` respectively. - (Contributed by Sergey B Kirpichev in :gh:`146151`.) + formatting characters ``'F'``/``'Zf'`` and ``'D'``/``'Zd'`` respectively. + (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Support half-floats (16-bit IEEE 754 binary interchange format): formatting character ``'e'``. (Contributed by Sergey B Kirpichev in :gh:`146238`.) +* The :data:`array.typecodes` type changed from :class:`str` to :class:`tuple` + to support type codes longer than 1 character (``Zf`` and ``Zd``). + (Contributed by Victor Stinner in :gh:`148675`.) + ast --- @@ -1741,6 +1745,12 @@ ctypes which has been deprecated since Python 3.13. (Contributed by Bénédikt Tran in :gh:`133866`.) +* Change the :py:attr:`~ctypes._SimpleCData._type_` of + :class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and + :class:`~ctypes.c_longdouble_complex` from ``F``, ``D`` and ``G`` to ``Zf``, + ``Zd`` and ``Zg`` for compatibility with numpy. + (Contributed by Victor Stinner in :gh:`148675`.) + datetime -------- diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index 6d7cb56f6c354e..0b84a27f8c6d61 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -206,13 +206,13 @@ class c_longdouble(_SimpleCData): try: class c_double_complex(_SimpleCData): - _type_ = "D" + _type_ = "Zd" _check_size(c_double_complex) class c_float_complex(_SimpleCData): - _type_ = "F" + _type_ = "Zf" _check_size(c_float_complex) class c_longdouble_complex(_SimpleCData): - _type_ = "G" + _type_ = "Zg" except AttributeError: pass diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 4493349798d9c8..54ecc886917dc7 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -31,7 +31,10 @@ class ArraySubclassWithKwargs(array.array): def __init__(self, typecode, newarg=None): array.array.__init__(self) -typecodes = 'uwbBhHiIlLfdqQFDe' +typecodes = ( + 'u', 'w', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', + 'f', 'd', 'q', 'Q', 'F', 'D', 'e', 'Zf', 'Zd') + class MiscTest(unittest.TestCase): @@ -42,8 +45,9 @@ def test_array_is_sequence(self): def test_bad_constructor(self): self.assertRaises(TypeError, array.array) self.assertRaises(TypeError, array.array, spam=42) - self.assertRaises(TypeError, array.array, 'xx') + self.assertRaises(ValueError, array.array, 'xx') self.assertRaises(ValueError, array.array, 'x') + self.assertRaises(ValueError, array.array, 'Z') @support.cpython_only def test_disallow_instantiation(self): @@ -85,6 +89,12 @@ def __index__(self): with self.assertRaises(TypeError): a.fromlist(lst) + def test_typecodes(self): + self.assertIsInstance(array.typecodes, tuple) + for typecode in array.typecodes: + self.assertIsInstance(typecode, str) + self.assertGreaterEqual(len(typecode), 1) + # Machine format codes. # @@ -208,6 +218,14 @@ def test_numbers(self): [9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]), (['D'], IEEE_754_DOUBLE_COMPLEX_BE, '>DDDD', [9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]), + (['Zf'], IEEE_754_FLOAT_COMPLEX_LE, 'ZfZfZfZf', + [16711938.0j, float('inf'), complex('1-infj'), -0.0]), + (['Zd'], IEEE_754_DOUBLE_COMPLEX_LE, 'ZdZdZdZd', + [9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]), ) for testcase in testcases: valid_typecodes, mformat_code, struct_fmt, values = testcase @@ -1237,6 +1255,9 @@ def test_free_after_iterating(self): support.check_free_after_iterating(self, reversed, array.array, (self.typecode,)) + def test_known_typecode(self): + self.assertIn(self.typecode, array.typecodes) + class StringTest(BaseTest): def test_setitem(self): @@ -1576,7 +1597,7 @@ def test_nan(self): def test_byteswap(self): a = array.array(self.typecode, self.example) self.assertRaises(TypeError, a.byteswap, 42) - if a.itemsize in (1, 2, 4, 8): + if a.itemsize in (1, 2, 4, 8, 16): b = array.array(self.typecode, self.example) b.byteswap() if a.itemsize == 1: @@ -1631,6 +1652,14 @@ class ComplexDoubleTest(CFPTest, unittest.TestCase): typecode = 'D' minitemsize = 16 +class ComplexZfFloatTest(CFPTest, unittest.TestCase): + typecode = 'Zf' + minitemsize = 8 + +class ComplexZdDoubleTest(CFPTest, unittest.TestCase): + typecode = 'Zd' + minitemsize = 16 + class LargeArrayTest(unittest.TestCase): typecode = 'b' diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 5a4f031e298c2f..21a3d0b3422ad2 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -67,7 +67,7 @@ 'h':0, 'H':0, 'i':0, 'I':0, 'l':0, 'L':0, 'n':0, 'N':0, 'e':0, 'f':0, 'd':0, 'P':0, - 'F':0, 'D':0 + 'F':0, 'D':0, 'Zf':0, 'Zd':0, } # NumPy does not have 'n' or 'N': @@ -95,7 +95,9 @@ 'e':(-65519, 65520), 'f':(-(1<<63), 1<<63), 'd':(-(1<<1023), 1<<1023), 'F':(-(1<<63), 1<<63), - 'D':(-(1<<1023), 1<<1023) + 'D':(-(1<<1023), 1<<1023), + 'Zf':(-(1<<63), 1<<63), + 'Zd':(-(1<<1023), 1<<1023), } def native_type_range(fmt): @@ -110,9 +112,9 @@ def native_type_range(fmt): lh = (-(1<<63), 1<<63) elif fmt == 'd': lh = (-(1<<1023), 1<<1023) - elif fmt == 'F': + elif fmt in ('F', 'Zf'): lh = (-(1<<63), 1<<63) - elif fmt == 'D': + elif fmt in ('D', 'Zd'): lh = (-(1<<1023), 1<<1023) else: for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7): @@ -182,18 +184,28 @@ def randrange_fmt(mode, char, obj): if char in 'efd': x = struct.pack(char, x) x = struct.unpack(char, x)[0] - if char in 'FD': + if char in ('F', 'D', 'Zf', 'Zd'): y = randrange(*fmtdict[mode][char]) x = complex(x, y) x = struct.pack(char, x) x = struct.unpack(char, x)[0] return x +def split_format(fmt): + i = 0 + while i < len(fmt): + if fmt[i] == 'Z': + n = 2 + else: + n = 1 + yield fmt[i:i + n] + i += n + def gen_item(fmt, obj): """Return single random item.""" mode, chars = fmt.split('#') x = [] - for c in chars: + for c in split_format(chars): x.append(randrange_fmt(mode, c, obj)) return x[0] if len(x) == 1 else tuple(x) @@ -254,9 +266,7 @@ def is_byte_format(fmt): def is_memoryview_format(fmt): """format suitable for memoryview""" - x = len(fmt) - return ((x == 1 or (x == 2 and fmt[0] == '@')) and - fmt[x-1] in MEMORYVIEW) + return fmt.removeprefix('@') in MEMORYVIEW NON_BYTE_FORMAT = [c for c in fmtdict['@'] if not is_byte_format(c)] @@ -648,14 +658,22 @@ def ndarray_from_structure(items, fmt, t, flags=0): return ndarray(items, shape=shape, strides=strides, format=fmt, offset=offset, flags=ND_WRITABLE|flags) +# Convert PEP 3118 formats to numpy dtypes +FORMAT_TO_DTYPE = { + 'Zf': 'F', + 'Zd': 'D', +} + def numpy_array_from_structure(items, fmt, t): """Return numpy_array from the tuple returned by rand_structure()""" memlen, itemsize, ndim, shape, strides, offset = t buf = bytearray(memlen) for j, v in enumerate(items): struct.pack_into(fmt, buf, j*itemsize, v) + # Replace Zd/Zf formats with D/F dtypes + dtype = FORMAT_TO_DTYPE.get(fmt, fmt) return numpy_array(buffer=buf, shape=shape, strides=strides, - dtype=fmt, offset=offset) + dtype=dtype, offset=offset) # ====================================================================== @@ -3037,7 +3055,7 @@ def test_memoryview_assign(self): continue m2 = m1.cast(fmt) lo, hi = _range - if fmt in "dfDF": + if fmt in ("d", "f", "D", "F", "Zd", "Zf"): lo, hi = -2**1024, 2**1024 if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers self.assertRaises(ValueError, m2.__setitem__, 0, lo-1) diff --git a/Lib/test/test_ctypes/test_c_simple_type_meta.py b/Lib/test/test_ctypes/test_c_simple_type_meta.py index fd261acf49741f..3b4fcf9c42a138 100644 --- a/Lib/test/test_ctypes/test_c_simple_type_meta.py +++ b/Lib/test/test_ctypes/test_c_simple_type_meta.py @@ -213,14 +213,12 @@ def test_bad_type_message(self): class F(metaclass=PyCSimpleType): _type_ = "\0" message = str(cm.exception) - expected_type_chars = list('cbBhHiIlLdDFGfuzZqQPXOv?g') - if not hasattr(ctypes, 'c_float_complex'): - expected_type_chars.remove('F') - expected_type_chars.remove('D') - expected_type_chars.remove('G') + expected_type_chars = list('cbBhHiIlLdfuzZqQPXOv?g') if not MS_WINDOWS: expected_type_chars.remove('X') self.assertIn("'" + ''.join(expected_type_chars) + "'", message) + if hasattr(ctypes, 'c_float_complex'): + self.assertIn("'Zf', 'Zd', 'Zg'", message) def test_creating_pointer_in_dunder_init_3(self): """Check if interfcase subclasses properly creates according internal diff --git a/Lib/test/test_ctypes/test_numbers.py b/Lib/test/test_ctypes/test_numbers.py index c57c58eb002328..b7df08f6079cd3 100644 --- a/Lib/test/test_ctypes/test_numbers.py +++ b/Lib/test/test_ctypes/test_numbers.py @@ -119,8 +119,11 @@ def test_floats(self): @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") def test_complex(self): - for t in [ctypes.c_double_complex, ctypes.c_float_complex, - ctypes.c_longdouble_complex]: + for format, t in [ + ('Zd', ctypes.c_double_complex), + ('Zf', ctypes.c_float_complex), + ('Zg', ctypes.c_longdouble_complex), + ]: self.assertEqual(t(1).value, 1+0j) self.assertEqual(t(1.0).value, 1+0j) self.assertEqual(t(1+0.125j).value, 1+0.125j) @@ -128,6 +131,12 @@ def test_complex(self): self.assertEqual(t(FloatLike()).value, 2+0j) self.assertEqual(t(ComplexLike()).value, 1+1j) + prefix = '>' if sys.byteorder == 'big' else '<' + num = t(1.0) + self.assertEqual(memoryview(num).format, prefix + format) + array = (t * 3)() + self.assertEqual(memoryview(array).format, prefix + format) + @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), "requires C11 complex type") def test_complex_round_trip(self): diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 820574584b56b2..f777ba583c5c06 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -637,7 +637,7 @@ def check_equal(view, is_equal): check_equal(m, True) # Test complex formats - for complex_format in 'FD': + for complex_format in ('F', 'D', 'Zf', 'Zd'): with self.subTest(format=complex_format): data = struct.pack(complex_format * 3, 1.0, 2.0, float('nan')) m = memoryview(data).cast(complex_format) @@ -723,6 +723,10 @@ def test_complex_types(self): double_complex_view = memoryview(double_complex_data).cast('D') self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes) self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist()) + float_complex_view = memoryview(float_complex_data).cast('Zf') + double_complex_view = memoryview(double_complex_data).cast('Zd') + self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes) + self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist()) def test_memoryview_hex(self): # Issue #9951: memoryview.hex() segfaults with non-contiguous buffers. diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 6479676f155eca..edd85df633fc3b 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -995,7 +995,11 @@ def test_c_complex_round_trip(self): values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2, -3, INF, -INF, NAN], 2)] for z in values: - for f in ['F', 'D', '>F', '>D', 'F', '>D', '>Zf', '>Zd', + '' : '<'; - result[1] = pep_code; - result[2] = '\0'; + strcpy(result + 1, pep_code); return result; } @@ -2347,7 +2345,6 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) { PyObject *proto; const char *proto_str; - Py_ssize_t proto_len; PyMethodDef *ml; struct fielddesc *fmt; @@ -2365,7 +2362,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) return -1; } if (PyUnicode_Check(proto)) { - proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len); + proto_str = PyUnicode_AsUTF8(proto); if (!proto_str) goto error; } else { @@ -2373,19 +2370,23 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) "class must define a '_type_' string attribute"); goto error; } - if (proto_len != 1) { - PyErr_SetString(PyExc_ValueError, - "class must define a '_type_' attribute " - "which must be a string of length 1"); - goto error; - } fmt = _ctypes_get_fielddesc(proto_str); if (!fmt) { - PyErr_Format(PyExc_AttributeError, - "class must define a '_type_' attribute which must be\n" - "a single character string containing one of the\n" - "supported types: '%s'.", - _ctypes_get_simple_type_chars()); + const char *complex_formats = _ctypes_get_complex_type_formats(); + if (complex_formats) { + PyErr_Format(PyExc_AttributeError, + "class must define a '_type_' attribute which must be\n" + "one of these characters: '%s',\n" + "or one of these strings: %s.", + _ctypes_get_simple_type_chars(), + complex_formats); + } + else { + PyErr_Format(PyExc_AttributeError, + "class must define a '_type_' attribute which must be\n" + "one of these characters: '%s'.\n", + _ctypes_get_simple_type_chars()); + } goto error; } @@ -2403,9 +2404,9 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) stginfo->setfunc = fmt->setfunc; stginfo->getfunc = fmt->getfunc; #ifdef WORDS_BIGENDIAN - stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 1); + stginfo->format = _ctypes_alloc_format_string_for_type(proto_str, 1); #else - stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0); + stginfo->format = _ctypes_alloc_format_string_for_type(proto_str, 0); #endif if (stginfo->format == NULL) { Py_DECREF(proto); @@ -2432,9 +2433,15 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) ml = c_char_p_methods; stginfo->flags |= TYPEFLAG_ISPOINTER; break; - case 'Z': /* c_wchar_p */ - ml = c_wchar_p_methods; - stginfo->flags |= TYPEFLAG_ISPOINTER; + case 'Z': + if (proto_str[1] == '\0') { + /* "Z": c_wchar_p */ + ml = c_wchar_p_methods; + stginfo->flags |= TYPEFLAG_ISPOINTER; + } + else { + ml = NULL; + } break; case 'P': /* c_void_p */ ml = c_void_p_methods; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 9a1c1ff8bb9cda..e208e27c5dbed4 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -641,9 +641,9 @@ union result { double d; float f; void *p; - double D[2]; - float F[2]; - long double G[2]; + double Zd[2]; + float Zf[2]; + long double Zg[2]; }; struct argument { diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index b0dc11fdddcea1..00b075bccff664 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -767,9 +767,9 @@ d_get(void *ptr, Py_ssize_t size) corresponding real type; the first element is equal to the real part, and the second element to the imaginary part, of the complex number." */ -/* D: double complex */ +/* Zd: double complex */ static PyObject * -D_set(void *ptr, PyObject *value, Py_ssize_t size) +Zd_set(void *ptr, PyObject *value, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(double))); Py_complex c = PyComplex_AsCComplex(value); @@ -783,7 +783,7 @@ D_set(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -D_get(void *ptr, Py_ssize_t size) +Zd_get(void *ptr, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(double))); double x[2]; @@ -793,7 +793,7 @@ D_get(void *ptr, Py_ssize_t size) } static PyObject * -D_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +Zd_set_sw(void *ptr, PyObject *value, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(double))); Py_complex c = PyComplex_AsCComplex(value); @@ -818,7 +818,7 @@ D_set_sw(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -D_get_sw(void *ptr, Py_ssize_t size) +Zd_get_sw(void *ptr, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(double))); #ifdef WORDS_BIGENDIAN @@ -830,9 +830,9 @@ D_get_sw(void *ptr, Py_ssize_t size) #endif } -/* F: float complex */ +/* Zf: float complex */ static PyObject * -F_set(void *ptr, PyObject *value, Py_ssize_t size) +Zf_set(void *ptr, PyObject *value, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(float))); Py_complex c = PyComplex_AsCComplex(value); @@ -846,7 +846,7 @@ F_set(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -F_get(void *ptr, Py_ssize_t size) +Zf_get(void *ptr, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(float))); float x[2]; @@ -856,7 +856,7 @@ F_get(void *ptr, Py_ssize_t size) } static PyObject * -F_set_sw(void *ptr, PyObject *value, Py_ssize_t size) +Zf_set_sw(void *ptr, PyObject *value, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(float))); Py_complex c = PyComplex_AsCComplex(value); @@ -881,7 +881,7 @@ F_set_sw(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -F_get_sw(void *ptr, Py_ssize_t size) +Zf_get_sw(void *ptr, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(float))); #ifdef WORDS_BIGENDIAN @@ -893,9 +893,9 @@ F_get_sw(void *ptr, Py_ssize_t size) #endif } -/* G: long double complex */ +/* Zg: long double complex */ static PyObject * -G_set(void *ptr, PyObject *value, Py_ssize_t size) +Zg_set(void *ptr, PyObject *value, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(long double))); Py_complex c = PyComplex_AsCComplex(value); @@ -909,7 +909,7 @@ G_set(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -G_get(void *ptr, Py_ssize_t size) +Zg_get(void *ptr, Py_ssize_t size) { assert(NUM_BITS(size) || (size == 2*sizeof(long double))); long double x[2]; @@ -917,7 +917,8 @@ G_get(void *ptr, Py_ssize_t size) memcpy(&x, ptr, sizeof(x)); return PyComplex_FromDoubles((double)x[0], (double)x[1]); } -#endif +#endif // _Py_FFI_SUPPORT_C_COMPLEX + /* d: double */ static PyObject * @@ -1451,7 +1452,7 @@ struct formattable { for nbytes in 8, 16, 32, 64: for sgn in 'i', 'u': print(f' struct fielddesc fmt_{sgn}{nbytes};') -for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO': +for code in 'sbBcdgfhHiIlLqQPzuUZXvO': print(f' struct fielddesc fmt_{code};') [python start generated code]*/ struct fielddesc fmt_i8; @@ -1467,9 +1468,6 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO': struct fielddesc fmt_B; struct fielddesc fmt_c; struct fielddesc fmt_d; - struct fielddesc fmt_F; - struct fielddesc fmt_D; - struct fielddesc fmt_G; struct fielddesc fmt_g; struct fielddesc fmt_f; struct fielddesc fmt_h; @@ -1488,7 +1486,10 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO': struct fielddesc fmt_X; struct fielddesc fmt_v; struct fielddesc fmt_O; -/*[python end generated code: output=f5a07c066fedaca6 input=ffa5d46c29dfb07a]*/ +/*[python end generated code: output=266ae6d30b6286a1 input=a1b7a263c7cf681f]*/ + struct fielddesc fmt_Zf; + struct fielddesc fmt_Zd; + struct fielddesc fmt_Zg; // bool has code '?': struct fielddesc fmt_bool; @@ -1498,7 +1499,7 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO': // Result of _ctypes_get_simple_type_chars. Initialized just after // the rest of formattable, so we stash it here. - char simple_type_chars[26]; + char simple_type_chars[23]; }; static struct formattable formattable; @@ -1617,7 +1618,7 @@ for base_code, base_c_type in [ (base_code.upper(), 'unsigned ' + base_c_type, 'u' + base_c_type), ]: print(f' formattable.fmt_{code} = *FIXINT_FIELDDESC_FOR({c_type});') - print(f" formattable.fmt_{code}.code = '{code}';") + print(f' formattable.fmt_{code}.code = "{code}";') if base_code == 'q': # ffi doesn't have `long long`; keep use the fixint type pass @@ -1625,34 +1626,34 @@ for base_code, base_c_type in [ print(f' formattable.fmt_{code}.pffi_type = &ffi_type_{ffi_type};') [python start generated code]*/ formattable.fmt_b = *FIXINT_FIELDDESC_FOR(signed char); - formattable.fmt_b.code = 'b'; + formattable.fmt_b.code = "b"; formattable.fmt_b.pffi_type = &ffi_type_schar; formattable.fmt_B = *FIXINT_FIELDDESC_FOR(unsigned char); - formattable.fmt_B.code = 'B'; + formattable.fmt_B.code = "B"; formattable.fmt_B.pffi_type = &ffi_type_uchar; formattable.fmt_h = *FIXINT_FIELDDESC_FOR(signed short); - formattable.fmt_h.code = 'h'; + formattable.fmt_h.code = "h"; formattable.fmt_h.pffi_type = &ffi_type_sshort; formattable.fmt_H = *FIXINT_FIELDDESC_FOR(unsigned short); - formattable.fmt_H.code = 'H'; + formattable.fmt_H.code = "H"; formattable.fmt_H.pffi_type = &ffi_type_ushort; formattable.fmt_i = *FIXINT_FIELDDESC_FOR(signed int); - formattable.fmt_i.code = 'i'; + formattable.fmt_i.code = "i"; formattable.fmt_i.pffi_type = &ffi_type_sint; formattable.fmt_I = *FIXINT_FIELDDESC_FOR(unsigned int); - formattable.fmt_I.code = 'I'; + formattable.fmt_I.code = "I"; formattable.fmt_I.pffi_type = &ffi_type_uint; formattable.fmt_l = *FIXINT_FIELDDESC_FOR(signed long); - formattable.fmt_l.code = 'l'; + formattable.fmt_l.code = "l"; formattable.fmt_l.pffi_type = &ffi_type_slong; formattable.fmt_L = *FIXINT_FIELDDESC_FOR(unsigned long); - formattable.fmt_L.code = 'L'; + formattable.fmt_L.code = "L"; formattable.fmt_L.pffi_type = &ffi_type_ulong; formattable.fmt_q = *FIXINT_FIELDDESC_FOR(signed long long); - formattable.fmt_q.code = 'q'; + formattable.fmt_q.code = "q"; formattable.fmt_Q = *FIXINT_FIELDDESC_FOR(unsigned long long); - formattable.fmt_Q.code = 'Q'; -/*[python end generated code: output=873c87a2e6b5075a input=ee814ca263aac18e]*/ + formattable.fmt_Q.code = "Q"; +/*[python end generated code: output=b91080b4b821a6da input=7356e281df4debd3]*/ /* Other types have bespoke setters and getters named `@_set` and `@_get`, @@ -1662,7 +1663,7 @@ for base_code, base_c_type in [ #define _TABLE_ENTRY(SYMBOL, FFI_TYPE, ...) \ formattable.fmt_ ## SYMBOL = \ - (struct fielddesc){(#SYMBOL)[0], (FFI_TYPE), __VA_ARGS__}; \ + (struct fielddesc){(#SYMBOL), (FFI_TYPE), __VA_ARGS__}; \ /////////////////////////////////////////////////////////////////////////// #define TABLE_ENTRY(SYMBOL, FFI_TYPE) \ @@ -1677,11 +1678,11 @@ for base_code, base_c_type in [ TABLE_ENTRY_SW(d, &ffi_type_double); #if defined(_Py_FFI_SUPPORT_C_COMPLEX) if (Py_FFI_COMPLEX_AVAILABLE) { - TABLE_ENTRY(D, &ffi_type_complex_double); - TABLE_ENTRY_SW(D, &ffi_type_complex_double); - TABLE_ENTRY(F, &ffi_type_complex_float); - TABLE_ENTRY_SW(F, &ffi_type_complex_float); - TABLE_ENTRY(G, &ffi_type_complex_longdouble); + TABLE_ENTRY(Zd, &ffi_type_complex_double); + TABLE_ENTRY_SW(Zd, &ffi_type_complex_double); + TABLE_ENTRY(Zf, &ffi_type_complex_float); + TABLE_ENTRY_SW(Zf, &ffi_type_complex_float); + TABLE_ENTRY(Zg, &ffi_type_complex_longdouble); } #endif TABLE_ENTRY(g, &ffi_type_longdouble); @@ -1711,12 +1712,12 @@ for base_code, base_c_type in [ // ctypes.c_bool is unsigned for FFI, even where C bool is signed. formattable.fmt_bool = *_ctypes_fixint_fielddesc(sizeof(bool), false); - formattable.fmt_bool.code = '?'; + formattable.fmt_bool.code = "?"; formattable.fmt_bool.setfunc = bool_set; formattable.fmt_bool.getfunc = bool_get; /*[python input] -all_chars = "cbBhHiIlLdDFGfuzZqQPXOv?g" +all_chars = "cbBhHiIlLdfuzZqQPXOv?g" print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});') print(f' int i = 0;') for char in all_chars: @@ -1725,7 +1726,7 @@ for char in all_chars: + f"formattable.simple_type_chars[i++] = '{char}';") print(f" formattable.simple_type_chars[i] = 0;") [python start generated code]*/ - assert(sizeof(formattable.simple_type_chars) == 26); + assert(sizeof(formattable.simple_type_chars) == 23); int i = 0; if (formattable.fmt_c.code) formattable.simple_type_chars[i++] = 'c'; if (formattable.fmt_b.code) formattable.simple_type_chars[i++] = 'b'; @@ -1737,9 +1738,6 @@ print(f" formattable.simple_type_chars[i] = 0;") if (formattable.fmt_l.code) formattable.simple_type_chars[i++] = 'l'; if (formattable.fmt_L.code) formattable.simple_type_chars[i++] = 'L'; if (formattable.fmt_d.code) formattable.simple_type_chars[i++] = 'd'; - if (formattable.fmt_D.code) formattable.simple_type_chars[i++] = 'D'; - if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F'; - if (formattable.fmt_G.code) formattable.simple_type_chars[i++] = 'G'; if (formattable.fmt_f.code) formattable.simple_type_chars[i++] = 'f'; if (formattable.fmt_u.code) formattable.simple_type_chars[i++] = 'u'; if (formattable.fmt_z.code) formattable.simple_type_chars[i++] = 'z'; @@ -1753,24 +1751,34 @@ print(f" formattable.simple_type_chars[i] = 0;") if (formattable.fmt_bool.code) formattable.simple_type_chars[i++] = '?'; if (formattable.fmt_g.code) formattable.simple_type_chars[i++] = 'g'; formattable.simple_type_chars[i] = 0; -/*[python end generated code: output=2aa52670d1570f18 input=cff3e7cb95adac61]*/ +/*[python end generated code: output=b78c8b7eed73d45a input=30ddc50637dd8ee4]*/ } #undef FIXINT_FIELDDESC_FOR _Py_COMP_DIAG_POP -char * +const char* _ctypes_get_simple_type_chars(void) { return formattable.simple_type_chars; } +const char* +_ctypes_get_complex_type_formats(void) { + if (Py_FFI_COMPLEX_AVAILABLE) { + return "'Zf', 'Zd', 'Zg'"; + } + else { + return NULL; + } +} + struct fielddesc * _ctypes_get_fielddesc(const char *fmt) { struct fielddesc *result = NULL; switch(fmt[0]) { /*[python input] -for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO': +for code in 'sbBcdgfhHiIlLqQPzuUXvO': print(f" case '{code}': result = &formattable.fmt_{code}; break;") [python start generated code]*/ case 's': result = &formattable.fmt_s; break; @@ -1778,9 +1786,6 @@ for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO': case 'B': result = &formattable.fmt_B; break; case 'c': result = &formattable.fmt_c; break; case 'd': result = &formattable.fmt_d; break; - case 'D': result = &formattable.fmt_D; break; - case 'F': result = &formattable.fmt_F; break; - case 'G': result = &formattable.fmt_G; break; case 'g': result = &formattable.fmt_g; break; case 'f': result = &formattable.fmt_f; break; case 'h': result = &formattable.fmt_h; break; @@ -1795,16 +1800,34 @@ for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO': case 'z': result = &formattable.fmt_z; break; case 'u': result = &formattable.fmt_u; break; case 'U': result = &formattable.fmt_U; break; - case 'Z': result = &formattable.fmt_Z; break; case 'X': result = &formattable.fmt_X; break; case 'v': result = &formattable.fmt_v; break; case 'O': result = &formattable.fmt_O; break; -/*[python end generated code: output=6e5c91940732fde9 input=902223feffc2fe38]*/ +/*[python end generated code: output=8e95bd0d49efb1c8 input=82d4ee1538b9b282]*/ + case 'Z': { + switch(fmt[1]) { + case '\0': result = &formattable.fmt_Z; break; + case 'd': result = &formattable.fmt_Zd; break; + case 'f': result = &formattable.fmt_Zf; break; + case 'g': result = &formattable.fmt_Zg; break; + } + break; + } case '?': result = &formattable.fmt_bool; break; } if (!result || !result->code) { return NULL; } + if (fmt[1] != '\0') { + if (fmt[0] == 'Z') { + if (fmt[2] != '\0') { + return NULL; + } + } + else { + return NULL; + } + } assert(result->pffi_type); assert(result->setfunc); assert(result->getfunc); diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 21743eb80ee976..7b6b7f08582251 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -280,7 +280,7 @@ extern CThunkObject *_ctypes_alloc_callback(ctypes_state *st, int flags); /* a table entry describing a predefined ctypes type */ struct fielddesc { - char code; + const char *code; ffi_type *pffi_type; /* always statically allocated */ SETFUNC setfunc; GETFUNC getfunc; @@ -289,7 +289,8 @@ struct fielddesc { }; // Get all single-character type codes (for use in error messages) -extern char *_ctypes_get_simple_type_chars(void); +extern const char* _ctypes_get_simple_type_chars(void); +extern const char* _ctypes_get_complex_type_formats(void); typedef struct CFieldObject { PyObject_HEAD diff --git a/Modules/_struct.c b/Modules/_struct.c index 47119cb3961e3c..3a970d99bb3d6d 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -45,7 +45,7 @@ static struct PyModuleDef _structmodule; /* The translation function for each format character is table driven */ typedef struct _formatdef { - char format; + const char *format; Py_ssize_t size; Py_ssize_t alignment; PyObject* (*unpack)(_structmodulestate *, const char *, @@ -327,13 +327,13 @@ _range_error(_structmodulestate *state, const formatdef *f, int is_unsigned) assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T); if (is_unsigned) PyErr_Format(state->StructError, - "'%c' format requires 0 <= number <= %zu", + "'%s' format requires 0 <= number <= %zu", f->format, ulargest); else { const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1); PyErr_Format(state->StructError, - "'%c' format requires %zd <= number <= %zd", + "'%s' format requires %zd <= number <= %zd", f->format, ~ largest, largest); @@ -708,7 +708,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) if (get_longlong(state, v, &x) < 0) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Format(state->StructError, - "'%c' format requires %lld <= number <= %lld", + "'%s' format requires %lld <= number <= %lld", f->format, LLONG_MIN, LLONG_MAX); @@ -726,7 +726,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f if (get_ulonglong(state, v, &x) < 0) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Format(state->StructError, - "'%c' format requires 0 <= number <= %llu", + "'%s' format requires 0 <= number <= %llu", f->format, ULLONG_MAX); } @@ -835,29 +835,31 @@ np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } static const formatdef native_table[] = { - {'x', sizeof(char), 0, NULL}, - {'b', sizeof(char), 0, nu_byte, np_byte}, - {'B', sizeof(char), 0, nu_ubyte, np_ubyte}, - {'c', sizeof(char), 0, nu_char, np_char}, - {'s', sizeof(char), 0, NULL}, - {'p', sizeof(char), 0, NULL}, - {'h', sizeof(short), _Alignof(short), nu_short, np_short}, - {'H', sizeof(short), _Alignof(short), nu_ushort, np_ushort}, - {'i', sizeof(int), _Alignof(int), nu_int, np_int}, - {'I', sizeof(int), _Alignof(int), nu_uint, np_uint}, - {'l', sizeof(long), _Alignof(long), nu_long, np_long}, - {'L', sizeof(long), _Alignof(long), nu_ulong, np_ulong}, - {'n', sizeof(size_t), _Alignof(size_t), nu_ssize_t, np_ssize_t}, - {'N', sizeof(size_t), _Alignof(size_t), nu_size_t, np_size_t}, - {'q', sizeof(long long), _Alignof(long long), nu_longlong, np_longlong}, - {'Q', sizeof(long long), _Alignof(long long), nu_ulonglong,np_ulonglong}, - {'?', sizeof(_Bool), _Alignof(_Bool), nu_bool, np_bool}, - {'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat}, - {'f', sizeof(float), _Alignof(float), nu_float, np_float}, - {'d', sizeof(double), _Alignof(double), nu_double, np_double}, - {'F', 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex}, - {'D', 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex}, - {'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p}, + {"x", sizeof(char), 0, NULL}, + {"b", sizeof(char), 0, nu_byte, np_byte}, + {"B", sizeof(char), 0, nu_ubyte, np_ubyte}, + {"c", sizeof(char), 0, nu_char, np_char}, + {"s", sizeof(char), 0, NULL}, + {"p", sizeof(char), 0, NULL}, + {"h", sizeof(short), _Alignof(short), nu_short, np_short}, + {"H", sizeof(short), _Alignof(short), nu_ushort, np_ushort}, + {"i", sizeof(int), _Alignof(int), nu_int, np_int}, + {"I", sizeof(int), _Alignof(int), nu_uint, np_uint}, + {"l", sizeof(long), _Alignof(long), nu_long, np_long}, + {"L", sizeof(long), _Alignof(long), nu_ulong, np_ulong}, + {"n", sizeof(size_t), _Alignof(size_t), nu_ssize_t, np_ssize_t}, + {"N", sizeof(size_t), _Alignof(size_t), nu_size_t, np_size_t}, + {"q", sizeof(long long), _Alignof(long long), nu_longlong, np_longlong}, + {"Q", sizeof(long long), _Alignof(long long), nu_ulonglong,np_ulonglong}, + {"?", sizeof(_Bool), _Alignof(_Bool), nu_bool, np_bool}, + {"e", sizeof(short), _Alignof(short), nu_halffloat, np_halffloat}, + {"f", sizeof(float), _Alignof(float), nu_float, np_float}, + {"d", sizeof(double), _Alignof(double), nu_double, np_double}, + {"F", 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex}, + {"D", 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex}, + {"Zf", 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex}, + {"Zd", 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex}, + {"P", sizeof(void *), _Alignof(void *), nu_void_p, np_void_p}, {0} }; @@ -1063,7 +1065,7 @@ bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_DECREF(v); if (res < 0) { PyErr_Format(state->StructError, - "'%c' format requires %lld <= number <= %lld", + "'%s' format requires %lld <= number <= %lld", f->format, LLONG_MIN, LLONG_MAX); @@ -1088,7 +1090,7 @@ bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f Py_DECREF(v); if (res < 0) { PyErr_Format(state->StructError, - "'%c' format requires 0 <= number <= %llu", + "'%s' format requires 0 <= number <= %llu", f->format, ULLONG_MAX); return -1; @@ -1168,26 +1170,28 @@ bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) } static formatdef bigendian_table[] = { - {'x', 1, 0, NULL}, - {'b', 1, 0, nu_byte, np_byte}, - {'B', 1, 0, nu_ubyte, np_ubyte}, - {'c', 1, 0, nu_char, np_char}, - {'s', 1, 0, NULL}, - {'p', 1, 0, NULL}, - {'h', 2, 0, bu_short, bp_int}, - {'H', 2, 0, bu_uint, bp_uint}, - {'i', 4, 0, bu_int, bp_int}, - {'I', 4, 0, bu_uint, bp_uint}, - {'l', 4, 0, bu_int, bp_int}, - {'L', 4, 0, bu_uint, bp_uint}, - {'q', 8, 0, bu_longlong, bp_longlong}, - {'Q', 8, 0, bu_ulonglong, bp_ulonglong}, - {'?', 1, 0, bu_bool, bp_bool}, - {'e', 2, 0, bu_halffloat, bp_halffloat}, - {'f', 4, 0, bu_float, bp_float}, - {'d', 8, 0, bu_double, bp_double}, - {'F', 8, 0, bu_float_complex, bp_float_complex}, - {'D', 16, 0, bu_double_complex, bp_double_complex}, + {"x", 1, 0, NULL}, + {"b", 1, 0, nu_byte, np_byte}, + {"B", 1, 0, nu_ubyte, np_ubyte}, + {"c", 1, 0, nu_char, np_char}, + {"s", 1, 0, NULL}, + {"p", 1, 0, NULL}, + {"h", 2, 0, bu_short, bp_int}, + {"H", 2, 0, bu_uint, bp_uint}, + {"i", 4, 0, bu_int, bp_int}, + {"I", 4, 0, bu_uint, bp_uint}, + {"l", 4, 0, bu_int, bp_int}, + {"L", 4, 0, bu_uint, bp_uint}, + {"q", 8, 0, bu_longlong, bp_longlong}, + {"Q", 8, 0, bu_ulonglong, bp_ulonglong}, + {"?", 1, 0, bu_bool, bp_bool}, + {"e", 2, 0, bu_halffloat, bp_halffloat}, + {"f", 4, 0, bu_float, bp_float}, + {"d", 8, 0, bu_double, bp_double}, + {"F", 8, 0, bu_float_complex, bp_float_complex}, + {"D", 16, 0, bu_double_complex, bp_double_complex}, + {"Zf", 8, 0, bu_float_complex, bp_float_complex}, + {"Zd", 16, 0, bu_double_complex, bp_double_complex}, {0} }; @@ -1387,7 +1391,7 @@ lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_DECREF(v); if (res < 0) { PyErr_Format(state->StructError, - "'%c' format requires %lld <= number <= %lld", + "'%s' format requires %lld <= number <= %lld", f->format, LLONG_MIN, LLONG_MAX); @@ -1412,7 +1416,7 @@ lp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f Py_DECREF(v); if (res < 0) { PyErr_Format(state->StructError, - "'%c' format requires 0 <= number <= %llu", + "'%s' format requires 0 <= number <= %llu", f->format, ULLONG_MAX); return -1; @@ -1482,27 +1486,29 @@ lp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatd } static formatdef lilendian_table[] = { - {'x', 1, 0, NULL}, - {'b', 1, 0, nu_byte, np_byte}, - {'B', 1, 0, nu_ubyte, np_ubyte}, - {'c', 1, 0, nu_char, np_char}, - {'s', 1, 0, NULL}, - {'p', 1, 0, NULL}, - {'h', 2, 0, lu_short, lp_int}, - {'H', 2, 0, lu_uint, lp_uint}, - {'i', 4, 0, lu_int, lp_int}, - {'I', 4, 0, lu_uint, lp_uint}, - {'l', 4, 0, lu_int, lp_int}, - {'L', 4, 0, lu_uint, lp_uint}, - {'q', 8, 0, lu_longlong, lp_longlong}, - {'Q', 8, 0, lu_ulonglong, lp_ulonglong}, - {'?', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep, + {"x", 1, 0, NULL}, + {"b", 1, 0, nu_byte, np_byte}, + {"B", 1, 0, nu_ubyte, np_ubyte}, + {"c", 1, 0, nu_char, np_char}, + {"s", 1, 0, NULL}, + {"p", 1, 0, NULL}, + {"h", 2, 0, lu_short, lp_int}, + {"H", 2, 0, lu_uint, lp_uint}, + {"i", 4, 0, lu_int, lp_int}, + {"I", 4, 0, lu_uint, lp_uint}, + {"l", 4, 0, lu_int, lp_int}, + {"L", 4, 0, lu_uint, lp_uint}, + {"q", 8, 0, lu_longlong, lp_longlong}, + {"Q", 8, 0, lu_ulonglong, lp_ulonglong}, + {"?", 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep, but potentially different from native rep -- reuse bx_bool funcs. */ - {'e', 2, 0, lu_halffloat, lp_halffloat}, - {'f', 4, 0, lu_float, lp_float}, - {'d', 8, 0, lu_double, lp_double}, - {'F', 8, 0, lu_float_complex, lp_float_complex}, - {'D', 16, 0, lu_double_complex, lp_double_complex}, + {"e", 2, 0, lu_halffloat, lp_halffloat}, + {"f", 4, 0, lu_float, lp_float}, + {"d", 8, 0, lu_double, lp_double}, + {"F", 8, 0, lu_float_complex, lp_float_complex}, + {"D", 16, 0, lu_double_complex, lp_double_complex}, + {"Zf", 8, 0, lu_float_complex, lp_float_complex}, + {"Zd", 16, 0, lu_double_complex, lp_double_complex}, {0} }; @@ -1523,10 +1529,10 @@ init_endian_tables(void *Py_UNUSED(arg)) entry in the endian table and swap in the native implementations whenever possible (64-bit platforms may not have "standard" sizes) */ - while (native->format != '\0' && other->format != '\0') { + while (native->format != NULL && other->format != NULL) { ptr = other; - while (ptr->format != '\0') { - if (ptr->format == native->format) { + while (ptr->format != NULL) { + if (strcmp(ptr->format, native->format) == 0) { /* Match faster when formats are listed in the same order */ if (ptr == other) @@ -1536,8 +1542,9 @@ init_endian_tables(void *Py_UNUSED(arg)) if (ptr->size != native->size) break; /* Skip _Bool, semantics are different for standard size */ - if (ptr->format == '?') + if (strcmp(ptr->format, "?") == 0) { break; + } ptr->pack = native->pack; ptr->unpack = native->unpack; break; @@ -1576,13 +1583,28 @@ whichtable(const char **pfmt) } +static int +format_equal(const formatdef *e, const char *s) +{ + const char *format = e->format; + size_t i = 0; + while (format[i] == s[i]) { + i++; + if (format[i] == 0) { + return 1; + } + } + return 0; +} + + /* Get the table entry for a format code */ static const formatdef * -getentry(_structmodulestate *state, int c, const formatdef *f) +getentry(_structmodulestate *state, const char *s, const formatdef *f) { - for (; f->format != '\0'; f++) { - if (f->format == c) { + for (; f->format != NULL; f++) { + if (format_equal(f, s)) { return f; } } @@ -1594,11 +1616,11 @@ getentry(_structmodulestate *state, int c, const formatdef *f) /* Align a size according to a format code. Return -1 on overflow. */ static Py_ssize_t -align(Py_ssize_t size, char c, const formatdef *e) +align(Py_ssize_t size, const char *s, const formatdef *e) { Py_ssize_t extra; - if (e->format == c) { + if (format_equal(e, s)) { if (e->alignment && size > 0) { extra = (e->alignment - 1) - (size - 1) % (e->alignment); if (extra > PY_SSIZE_T_MAX - size) @@ -1670,7 +1692,8 @@ prepare_s(PyStructObject *self, PyObject *format) else num = 1; - e = getentry(state, c, f); + s--; + e = getentry(state, s, f); if (e == NULL) return -1; @@ -1696,9 +1719,10 @@ prepare_s(PyStructObject *self, PyObject *format) } itemsize = e->size; - size = align(size, c, e); + size = align(size, s, e); if (size == -1) goto overflow; + s += strlen(e->format); /* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */ if (num > (PY_SSIZE_T_MAX - size) / itemsize) @@ -1731,9 +1755,11 @@ prepare_s(PyStructObject *self, PyObject *format) else num = 1; - e = getentry(state, c, f); + s--; + e = getentry(state, s, f); + size = align(size, s, e); + s += strlen(e->format); - size = align(size, c, e); if (c == 's' || c == 'p') { codes->offset = size; codes->size = num; @@ -2024,9 +2050,9 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom, Py_ssize_t j = code->repeat; while (j--) { PyObject *v; - if (e->format == 's') { + if (strcmp(e->format, "s") == 0) { v = PyBytes_FromStringAndSize(res, code->size); - } else if (e->format == 'p') { + } else if (strcmp(e->format, "p") == 0) { Py_ssize_t n; if (code->size == 0) { n = 0; @@ -2319,7 +2345,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, Py_ssize_t j = code->repeat; while (j--) { PyObject *v = args[i++]; - if (e->format == 's') { + if (strcmp(e->format, "s") == 0) { Py_ssize_t n; int isstring; const void *p; @@ -2341,7 +2367,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, n = code->size; if (n > 0) memcpy(res, p, n); - } else if (e->format == 'p') { + } else if (strcmp(e->format, "p") == 0) { Py_ssize_t n; int isstring; const void *p; diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index b01e92eb8873ba..56a2a98fe42731 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -33,12 +33,11 @@ static struct PyModuleDef arraymodule; * functions aren't visible yet. */ struct arraydescr { - char typecode; + const char *typecode; int itemsize; PyObject * (*getitem)(struct arrayobject *, Py_ssize_t); int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *); int (*compareitems)(const void *, const void *, Py_ssize_t); - const char *formats; int is_integer_type; int is_signed; }; @@ -768,24 +767,26 @@ DEFINE_COMPAREITEMS(QQ, unsigned long long) * typecode. */ static const struct arraydescr descriptors[] = { - {'b', 1, b_getitem, b_setitem, b_compareitems, "b", 1, 1}, - {'B', 1, BB_getitem, BB_setitem, BB_compareitems, "B", 1, 0}, - {'u', sizeof(wchar_t), u_getitem, u_setitem, u_compareitems, "u", 0, 0}, - {'w', sizeof(Py_UCS4), w_getitem, w_setitem, w_compareitems, "w", 0, 0,}, - {'h', sizeof(short), h_getitem, h_setitem, h_compareitems, "h", 1, 1}, - {'H', sizeof(short), HH_getitem, HH_setitem, HH_compareitems, "H", 1, 0}, - {'i', sizeof(int), i_getitem, i_setitem, i_compareitems, "i", 1, 1}, - {'I', sizeof(int), II_getitem, II_setitem, II_compareitems, "I", 1, 0}, - {'l', sizeof(long), l_getitem, l_setitem, l_compareitems, "l", 1, 1}, - {'L', sizeof(long), LL_getitem, LL_setitem, LL_compareitems, "L", 1, 0}, - {'q', sizeof(long long), q_getitem, q_setitem, q_compareitems, "q", 1, 1}, - {'Q', sizeof(long long), QQ_getitem, QQ_setitem, QQ_compareitems, "Q", 1, 0}, - {'e', sizeof(short), e_getitem, e_setitem, NULL, "e", 0, 0}, - {'f', sizeof(float), f_getitem, f_setitem, NULL, "f", 0, 0}, - {'d', sizeof(double), d_getitem, d_setitem, NULL, "d", 0, 0}, - {'F', 2*sizeof(float), cf_getitem, cf_setitem, NULL, "F", 0, 0}, - {'D', 2*sizeof(double), cd_getitem, cd_setitem, NULL, "D", 0, 0}, - {'\0', 0, 0, 0, 0, 0, 0} /* Sentinel */ + {"b", 1, b_getitem, b_setitem, b_compareitems, 1, 1}, + {"B", 1, BB_getitem, BB_setitem, BB_compareitems, 1, 0}, + {"u", sizeof(wchar_t), u_getitem, u_setitem, u_compareitems, 0, 0}, + {"w", sizeof(Py_UCS4), w_getitem, w_setitem, w_compareitems, 0, 0,}, + {"h", sizeof(short), h_getitem, h_setitem, h_compareitems, 1, 1}, + {"H", sizeof(short), HH_getitem, HH_setitem, HH_compareitems, 1, 0}, + {"i", sizeof(int), i_getitem, i_setitem, i_compareitems, 1, 1}, + {"I", sizeof(int), II_getitem, II_setitem, II_compareitems, 1, 0}, + {"l", sizeof(long), l_getitem, l_setitem, l_compareitems, 1, 1}, + {"L", sizeof(long), LL_getitem, LL_setitem, LL_compareitems, 1, 0}, + {"q", sizeof(long long), q_getitem, q_setitem, q_compareitems, 1, 1}, + {"Q", sizeof(long long), QQ_getitem, QQ_setitem, QQ_compareitems, 1, 0}, + {"e", sizeof(short), e_getitem, e_setitem, NULL, 0, 0}, + {"f", sizeof(float), f_getitem, f_setitem, NULL, 0, 0}, + {"d", sizeof(double), d_getitem, d_setitem, NULL, 0, 0}, + {"F", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, + {"D", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, + {"Zf", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, + {"Zd", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, + {NULL, 0, 0, 0, 0, 0, 0} /* Sentinel */ }; /**************************************************************************** @@ -1611,7 +1612,9 @@ array_array_byteswap_impl(arrayobject *self) } break; case 8: - if (self->ob_descr->typecode != 'F') { + if (strcmp(self->ob_descr->typecode, "F") != 0 + && strcmp(self->ob_descr->typecode, "Zf") != 0) + { for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char p0 = p[0]; char p1 = p[1]; @@ -1645,7 +1648,8 @@ array_array_byteswap_impl(arrayobject *self) } break; case 16: - assert(self->ob_descr->typecode == 'D'); + assert(strcmp(self->ob_descr->typecode, "D") == 0 + || strcmp(self->ob_descr->typecode, "Zd") == 0); for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char t0 = p[0]; char t1 = p[1]; @@ -1985,15 +1989,15 @@ static PyObject * array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) /*[clinic end generated code: output=24359f5e001a7f2b input=158d47c302f27ca1]*/ { - int typecode = self->ob_descr->typecode; - if (typecode != 'u' && typecode != 'w') { + const char *typecode = self->ob_descr->typecode; + if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) { PyErr_SetString(PyExc_ValueError, "fromunicode() may only be called on " "unicode type arrays ('u' or 'w')"); return NULL; } - if (typecode == 'u') { + if (strcmp(typecode, "u") == 0) { Py_ssize_t ustr_length = PyUnicode_AsWideChar(ustr, NULL, 0); assert(ustr_length > 0); if (ustr_length > 1) { @@ -2008,7 +2012,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr) ustr, ((wchar_t *)self->ob_item) + old_size, ustr_length); } } - else { // typecode == 'w' + else { // typecode == "w" Py_ssize_t ustr_length = PyUnicode_GetLength(ustr); Py_ssize_t old_size = Py_SIZE(self); Py_ssize_t new_size = old_size + ustr_length; @@ -2045,16 +2049,16 @@ static PyObject * array_array_tounicode_impl(arrayobject *self) /*[clinic end generated code: output=08e442378336e1ef input=6690997213d219db]*/ { - int typecode = self->ob_descr->typecode; - if (typecode != 'u' && typecode != 'w') { + const char *typecode = self->ob_descr->typecode; + if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) { PyErr_SetString(PyExc_ValueError, "tounicode() may only be called on unicode type arrays ('u' or 'w')"); return NULL; } - if (typecode == 'u') { + if (strcmp(typecode, "u") == 0) { return PyUnicode_FromWideChar((wchar_t *) self->ob_item, Py_SIZE(self)); } - else { // typecode == 'w' + else { // typecode == "w" int byteorder = 0; // native byteorder return PyUnicode_DecodeUTF32((const char *) self->ob_item, Py_SIZE(self) * 4, NULL, &byteorder); @@ -2121,14 +2125,14 @@ static const struct mformatdescr { * be found. */ static enum machine_format_code -typecode_to_mformat_code(char typecode) +typecode_to_mformat_code(const char *typecode) { const int is_big_endian = PY_BIG_ENDIAN; size_t intsize; int is_signed; - switch (typecode) { + switch (typecode[0]) { case 'b': return SIGNED_INT8; case 'B': @@ -2163,6 +2167,21 @@ typecode_to_mformat_code(char typecode) return _PY_FLOAT_BIG_ENDIAN ? \ IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE; + case 'Z': { + switch (typecode[1]) { + case 'f': + return _PY_FLOAT_BIG_ENDIAN ? \ + IEEE_754_FLOAT_COMPLEX_BE : IEEE_754_FLOAT_COMPLEX_LE; + + case 'd': + return _PY_FLOAT_BIG_ENDIAN ? \ + IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE; + + default: + return UNKNOWN_FORMAT; + } + } + /* Integers */ case 'h': intsize = sizeof(short); @@ -2218,7 +2237,7 @@ static PyObject *array_new(PyTypeObject *type, PyObject *args, PyObject *kwds); * Internal: This function wraps the array constructor--i.e., array_new()--to * allow the creation of array objects from C code without having to deal * directly the tuple argument of array_new(). The typecode argument is a - * Unicode character value, like 'i' or 'f' for example, representing an array + * string, like "i" or "f" for example, representing an array * type code. The items argument is a bytes or a list object from which * contains the initial value of the array. * @@ -2226,7 +2245,7 @@ static PyObject *array_new(PyTypeObject *type, PyObject *args, PyObject *kwds); * NULL is returned to indicate a failure. */ static PyObject * -make_array(PyTypeObject *arraytype, char typecode, PyObject *items) +make_array(PyTypeObject *arraytype, const char *typecode, PyObject *items) { PyObject *new_args; PyObject *array_obj; @@ -2235,7 +2254,7 @@ make_array(PyTypeObject *arraytype, char typecode, PyObject *items) assert(arraytype != NULL); assert(items != NULL); - typecode_obj = PyUnicode_FromOrdinal(typecode); + typecode_obj = PyUnicode_FromString(typecode); if (typecode_obj == NULL) return NULL; @@ -2260,7 +2279,7 @@ make_array(PyTypeObject *arraytype, char typecode, PyObject *items) array._array_reconstructor arraytype: object(type="PyTypeObject *") - typecode: int(accept={str}) + typecode: str mformat_code: int(type="enum machine_format_code") items: object / @@ -2270,10 +2289,10 @@ Internal. Used for pickling support. static PyObject * array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, - int typecode, + const char *typecode, enum machine_format_code mformat_code, PyObject *items) -/*[clinic end generated code: output=e05263141ba28365 input=2464dc8f4c7736b5]*/ +/*[clinic end generated code: output=723e3813e0a18b7b input=9f1c331baae742a6]*/ { array_state *state = get_array_state(module); PyObject *converted_items; @@ -2292,11 +2311,12 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, arraytype->tp_name, state->ArrayType->tp_name); return NULL; } - for (descr = descriptors; descr->typecode != '\0'; descr++) { - if ((int)descr->typecode == typecode) + for (descr = descriptors; descr->typecode != NULL; descr++) { + if (strcmp(descr->typecode, typecode) == 0) { break; + } } - if (descr->typecode == '\0') { + if (descr->typecode == NULL) { PyErr_SetString(PyExc_ValueError, "second argument must be a valid type code"); return NULL; @@ -2315,9 +2335,9 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, } /* Fast path: No decoding has to be done. */ - if (mformat_code == typecode_to_mformat_code((char)typecode) || + if (mformat_code == typecode_to_mformat_code(typecode) || mformat_code == UNKNOWN_FORMAT) { - return make_array(arraytype, (char)typecode, items); + return make_array(arraytype, typecode, items); } /* Slow path: Decode the byte string according to the given machine @@ -2493,11 +2513,13 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, * * XXX: Is it possible to write a unit test for this? */ - for (descr = descriptors; descr->typecode != '\0'; descr++) { + for (descr = descriptors; descr->typecode != NULL; descr++) { if (descr->is_integer_type && (size_t)descr->itemsize == mf_descr.size && descr->is_signed == mf_descr.is_signed) + { typecode = descr->typecode; + } } converted_items = PyList_New(itemcount); @@ -2528,7 +2550,7 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, return NULL; } - result = make_array(arraytype, (char)typecode, converted_items); + result = make_array(arraytype, typecode, converted_items); Py_DECREF(converted_items); return result; } @@ -2551,7 +2573,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, PyObject *dict; PyObject *result; PyObject *array_str; - int typecode = self->ob_descr->typecode; + const char *typecode = self->ob_descr->typecode; int mformat_code; long protocol; @@ -2602,7 +2624,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, return NULL; } result = Py_BuildValue( - "O(CO)O", Py_TYPE(self), typecode, list, dict); + "O(sO)O", Py_TYPE(self), typecode, list, dict); Py_DECREF(list); Py_DECREF(dict); return result; @@ -2616,7 +2638,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls, assert(state->array_reconstructor != NULL); result = Py_BuildValue( - "O(OCiN)O", state->array_reconstructor, Py_TYPE(self), typecode, + "O(OsiN)O", state->array_reconstructor, Py_TYPE(self), typecode, mformat_code, array_str, dict); Py_DECREF(dict); return result; @@ -2626,8 +2648,8 @@ static PyObject * array_get_typecode(PyObject *op, void *Py_UNUSED(closure)) { arrayobject *a = arrayobject_CAST(op); - char typecode = a->ob_descr->typecode; - return PyUnicode_FromOrdinal(typecode); + const char *typecode = a->ob_descr->typecode; + return PyUnicode_FromString(typecode); } static PyObject * @@ -2676,7 +2698,7 @@ static PyMethodDef array_methods[] = { static PyObject * array_repr(PyObject *op) { - char typecode; + const char *typecode; PyObject *s, *v = NULL; Py_ssize_t len; arrayobject *a = arrayobject_CAST(op); @@ -2684,10 +2706,10 @@ array_repr(PyObject *op) len = Py_SIZE(a); typecode = a->ob_descr->typecode; if (len == 0) { - return PyUnicode_FromFormat("%s('%c')", - _PyType_Name(Py_TYPE(a)), (int)typecode); + return PyUnicode_FromFormat("%s('%s')", + _PyType_Name(Py_TYPE(a)), typecode); } - if (typecode == 'u' || typecode == 'w') { + if (strcmp(typecode, "u") == 0 || strcmp(typecode, "w") == 0) { v = array_array_tounicode_impl(a); } else { v = array_array_tolist_impl(a); @@ -2695,8 +2717,8 @@ array_repr(PyObject *op) if (v == NULL) return NULL; - s = PyUnicode_FromFormat("%s('%c', %R)", - _PyType_Name(Py_TYPE(a)), (int)typecode, v); + s = PyUnicode_FromFormat("%s('%s', %R)", + _PyType_Name(Py_TYPE(a)), typecode, v); Py_DECREF(v); return s; } @@ -2956,8 +2978,8 @@ array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) view->format = NULL; view->internal = NULL; if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) { - view->format = (char *)self->ob_descr->formats; - if (sizeof(wchar_t) >= 4 && self->ob_descr->typecode == 'u') { + view->format = (char *)self->ob_descr->typecode; + if (sizeof(wchar_t) >= 4 && strcmp(self->ob_descr->typecode, "u") == 0) { view->format = "w"; } } @@ -2977,7 +2999,7 @@ static PyObject * array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { array_state *state = find_array_state_by_type(type); - int c; + const char *s; PyObject *initial = NULL, *it = NULL; const struct arraydescr *descr; @@ -2986,15 +3008,15 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) !_PyArg_NoKeywords("array.array", kwds)) return NULL; - if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial)) + if (!PyArg_ParseTuple(args, "s|O:array", &s, &initial)) return NULL; - if (PySys_Audit("array.__new__", "CO", - c, initial ? initial : Py_None) < 0) { + if (PySys_Audit("array.__new__", "sO", + s, initial ? initial : Py_None) < 0) { return NULL; } - if (c == 'u') { + if (strcmp(s, "u") == 0) { if (PyErr_WarnEx(PyExc_DeprecationWarning, "The 'u' type code is deprecated and " "will be removed in Python 3.16", @@ -3003,19 +3025,19 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } } - bool is_unicode = c == 'u' || c == 'w'; + bool is_unicode = (strcmp(s, "u") == 0 || strcmp(s, "w") == 0); if (initial && !is_unicode) { if (PyUnicode_Check(initial)) { PyErr_Format(PyExc_TypeError, "cannot use a str to initialize " - "an array with typecode '%c'", c); + "an array with typecode '%s'", s); return NULL; } else if (array_Check(initial, state)) { - int ic = ((arrayobject*)initial)->ob_descr->typecode; - if (ic == 'u' || ic == 'w') { + const char *is = ((arrayobject*)initial)->ob_descr->typecode; + if (strcmp(is, "u") == 0 || strcmp(is, "w") == 0) { PyErr_Format(PyExc_TypeError, "cannot use a unicode array to " - "initialize an array with typecode '%c'", c); + "initialize an array with typecode '%s'", s); return NULL; } } @@ -3027,7 +3049,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) || PyTuple_Check(initial) || (is_unicode && PyUnicode_Check(initial)) || (array_Check(initial, state) - && c == ((arrayobject*)initial)->ob_descr->typecode))) { + && strcmp(s, ((arrayobject*)initial)->ob_descr->typecode) == 0))) { it = PyObject_GetIter(initial); if (it == NULL) return NULL; @@ -3038,8 +3060,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) */ initial = NULL; } - for (descr = descriptors; descr->typecode != '\0'; descr++) { - if (descr->typecode == c) { + for (descr = descriptors; descr->typecode != NULL; descr++) { + if (strcmp(descr->typecode, s) == 0) { PyObject *a; Py_ssize_t len; @@ -3089,7 +3111,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(v); } else if (initial != NULL && PyUnicode_Check(initial)) { - if (c == 'u') { + if (strcmp(s, "u") == 0) { Py_ssize_t n; wchar_t *ustr = PyUnicode_AsWideCharString(initial, &n); if (ustr == NULL) { @@ -3110,7 +3132,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyMem_Free(ustr); } } - else { // c == 'w' + else { // s == "w" Py_ssize_t n = PyUnicode_GET_LENGTH(initial); Py_UCS4 *ustr = PyUnicode_AsUCS4Copy(initial); if (ustr == NULL) { @@ -3145,7 +3167,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } Py_XDECREF(it); PyErr_SetString(PyExc_ValueError, - "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, f or d)"); + "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, e, f, d, F, D, Zf or Zd)"); return NULL; } @@ -3165,7 +3187,7 @@ string or iterable over elements of the appropriate type.\n\ \n\ Arrays represent basic values and behave very much like lists, except\n\ the type of objects stored in them is constrained. The type is specified\n\ -at object creation time by using a type code, which is a single character.\n\ +at object creation time by using a type code, which is a string.\n\ The following type codes are defined:\n\ \n\ Type code C Type Minimum size in bytes\n\ @@ -3185,6 +3207,8 @@ The following type codes are defined:\n\ 'd' floating-point 8\n\ 'F' float complex 8\n\ 'D' double complex 16\n\ + 'Zf' float complex 8\n\ + 'Zd' double complex 16\n\ \n\ NOTE: The 'u' typecode corresponds to Python's unicode character. On\n\ narrow builds this is 2-bytes on wide builds this is 4-bytes.\n\ @@ -3480,7 +3504,6 @@ static int array_modexec(PyObject *m) { array_state *state = get_array_state(m); - char buffer[Py_ARRAY_LENGTH(descriptors)], *p; PyObject *typecodes; const struct arraydescr *descr; @@ -3519,12 +3542,29 @@ array_modexec(PyObject *m) return -1; } - p = buffer; - for (descr = descriptors; descr->typecode != '\0'; descr++) { - *p++ = (char)descr->typecode; + typecodes = PyList_New(0); + if (typecodes == NULL) { + return -1; + } + for (descr = descriptors; descr->typecode != NULL; descr++) { + PyObject *typecode = PyUnicode_DecodeASCII(descr->typecode, strlen(descr->typecode), NULL); + if (typecode == NULL) { + Py_DECREF(typecodes); + return -1; + } + int res = PyList_Append(typecodes, typecode); + Py_DECREF(typecode); + if (res < 0) { + Py_DECREF(typecodes); + return -1; + } + } + PyObject *tuple = PyList_AsTuple(typecodes); + Py_DECREF(typecodes); + if (tuple == NULL) { + return -1; } - typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL); - if (PyModule_Add(m, "typecodes", typecodes) < 0) { + if (PyModule_Add(m, "typecodes", tuple) < 0) { return -1; } diff --git a/Modules/clinic/arraymodule.c.h b/Modules/clinic/arraymodule.c.h index 8a3fb4b515e4ac..eec47ab2b1f9e1 100644 --- a/Modules/clinic/arraymodule.c.h +++ b/Modules/clinic/arraymodule.c.h @@ -651,7 +651,7 @@ PyDoc_STRVAR(array__array_reconstructor__doc__, static PyObject * array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype, - int typecode, + const char *typecode, enum machine_format_code mformat_code, PyObject *items); @@ -660,7 +660,7 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n { PyObject *return_value = NULL; PyTypeObject *arraytype; - int typecode; + const char *typecode; enum machine_format_code mformat_code; PyObject *items; @@ -669,17 +669,18 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n } arraytype = (PyTypeObject *)args[0]; if (!PyUnicode_Check(args[1])) { - _PyArg_BadArgument("_array_reconstructor", "argument 2", "a unicode character", args[1]); + _PyArg_BadArgument("_array_reconstructor", "argument 2", "str", args[1]); goto exit; } - if (PyUnicode_GET_LENGTH(args[1]) != 1) { - PyErr_Format(PyExc_TypeError, - "_array_reconstructor(): argument 2 must be a unicode character, " - "not a string of length %zd", - PyUnicode_GET_LENGTH(args[1])); + Py_ssize_t typecode_length; + typecode = PyUnicode_AsUTF8AndSize(args[1], &typecode_length); + if (typecode == NULL) { + goto exit; + } + if (strlen(typecode) != (size_t)typecode_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); goto exit; } - typecode = PyUnicode_READ_CHAR(args[1], 0); mformat_code = PyLong_AsInt(args[2]); if (mformat_code == -1 && PyErr_Occurred()) { goto exit; @@ -779,4 +780,4 @@ array_arrayiterator___setstate__(PyObject *self, PyObject *state) return return_value; } -/*[clinic end generated code: output=9dcb2fc40710f83d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8699475b51151247 input=a9049054013a1b77]*/ diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index d0f414f7c4209b..2c2f85ebf6acc0 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -281,7 +281,7 @@ last_dim_is_contiguous(const Py_buffer *dest, const Py_buffer *src) /* This is not a general function for determining format equivalence. It is used in copy_single() and copy_buffer() to weed out non-matching formats. Skipping the '@' character is specifically used in slice - assignments, where the lvalue is already known to have a single character + assignments, where the lvalue is already known to have a format. This is a performance hack that could be rewritten (if properly benchmarked). */ static inline int @@ -1197,10 +1197,11 @@ memory_exit(PyObject *self, PyObject *args) /* Casting format and shape */ /****************************************************************************/ -#define IS_BYTE_FORMAT(f) (f == 'b' || f == 'B' || f == 'c') +#define IS_BYTE_FORMAT(f) \ + (strcmp(f, "b") == 0 || strcmp(f, "B") == 0 || strcmp(f, "c") == 0) static inline Py_ssize_t -get_native_fmtchar(char *result, const char *fmt) +get_native_fmtchar(const char **result, const char *fmt) { Py_ssize_t size = -1; @@ -1220,10 +1221,21 @@ get_native_fmtchar(char *result, const char *fmt) case 'D': size = 2*sizeof(double); break; case '?': size = sizeof(_Bool); break; case 'P': size = sizeof(void *); break; + case 'Z': { + switch (fmt[1]) { + case 'f': size = 2*sizeof(float); break; + case 'd': size = 2*sizeof(double); break; + } + if (size > 0 && fmt[2] == '\0') { + *result = fmt; + return size; + } + break; + } } if (size > 0 && fmt[1] == '\0') { - *result = fmt[0]; + *result = fmt; return size; } @@ -1239,9 +1251,19 @@ get_native_fmtstr(const char *fmt) at = 1; fmt++; } - if (fmt[0] == '\0' || fmt[1] != '\0') { + if (fmt[0] == '\0') { return NULL; } + if (fmt[0] == 'Z') { + if (fmt[1] == '\0' || fmt[2] != '\0') { + return NULL; + } + } + else { + if (fmt[1] != '\0') { + return NULL; + } + } #define RETURN(s) do { return at ? "@" s : s; } while (0) @@ -1264,6 +1286,13 @@ get_native_fmtstr(const char *fmt) case 'e': RETURN("e"); case 'F': RETURN("F"); case 'D': RETURN("D"); + case 'Z': { + switch (fmt[1]) { + case 'f': RETURN("Zf"); + case 'd': RETURN("Zd"); + } + break; + } case '?': RETURN("?"); case 'P': RETURN("P"); } @@ -1281,7 +1310,7 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format) { Py_buffer *view = &mv->view; PyObject *asciifmt; - char srcchar, destchar; + const char *srcfmt, *destfmt; Py_ssize_t itemsize; int ret = -1; @@ -1295,16 +1324,16 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format) if (asciifmt == NULL) return ret; - itemsize = get_native_fmtchar(&destchar, PyBytes_AS_STRING(asciifmt)); + itemsize = get_native_fmtchar(&destfmt, PyBytes_AS_STRING(asciifmt)); if (itemsize < 0) { PyErr_SetString(PyExc_ValueError, - "memoryview: destination format must be a native single " - "character format prefixed with an optional '@'"); + "memoryview: destination format must be a native " + "format prefixed with an optional '@'"); goto out; } - if ((get_native_fmtchar(&srcchar, view->format) < 0 || - !IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) { + if ((get_native_fmtchar(&srcfmt, view->format) < 0 || + !IS_BYTE_FORMAT(srcfmt)) && !IS_BYTE_FORMAT(destfmt)) { PyErr_SetString(PyExc_TypeError, "memoryview: cannot cast between two non-byte formats"); goto out; @@ -1846,6 +1875,23 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt) d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian); goto convert_double_complex; + case 'Z': { + switch (fmt[1]) { + case 'f': + d[0] = PyFloat_Unpack4(ptr, endian); + d[1] = PyFloat_Unpack4(ptr + sizeof(float), endian); + goto convert_double_complex; + + case 'd': + d[0] = PyFloat_Unpack8(ptr, endian); + d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian); + goto convert_double_complex; + + default: goto err_format; + } + break; + } + /* bytes object */ case 'c': goto convert_bytes; @@ -2027,6 +2073,31 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt } break; + case 'Z': { + switch (fmt[1]) { + case 'f': case 'd': + c = PyComplex_AsCComplex(item); + if (c.real == -1.0 && PyErr_Occurred()) { + goto err_occurred; + } + CHECK_RELEASED_INT_AGAIN(self); + if (fmt[1] == 'd') { + double x[2] = {c.real, c.imag}; + + memcpy(ptr, &x, sizeof(x)); + } + else { + float x[2] = {(float)c.real, (float)c.imag}; + + memcpy(ptr, &x, sizeof(x)); + } + break; + + default: goto err_format; + } + break; + } + /* bool */ case '?': ld = PyObject_IsTrue(item); @@ -2200,6 +2271,8 @@ adjust_fmt(const Py_buffer *view) const char *fmt; fmt = (view->format[0] == '@') ? view->format+1 : view->format; + if (fmt[0] == 'Z' && fmt[1] && fmt[2] == '\0') + return fmt; if (fmt[0] && fmt[1] == '\0') return fmt; @@ -3018,12 +3091,12 @@ struct_unpack_cmp(const char *p, const char *q, } while (0) static inline int -unpack_cmp(const char *p, const char *q, char fmt, +unpack_cmp(const char *p, const char *q, const char *fmt, struct unpacker *unpack_p, struct unpacker *unpack_q) { int equal; - switch (fmt) { + switch (fmt[0]) { /* signed integers and fast path for 'B' */ case 'B': return *((const unsigned char *)p) == *((const unsigned char *)q); @@ -3081,6 +3154,27 @@ unpack_cmp(const char *p, const char *q, char fmt, memcpy(&y, q, sizeof(y)); return (x[0] == y[0]) && (x[1] == y[1]); } + case 'Z': { + switch (fmt[1]) { + case 'f': + { + float x[2], y[2]; + + memcpy(&x, p, sizeof(x)); + memcpy(&y, q, sizeof(y)); + return (x[0] == y[0]) && (x[1] == y[1]); + } + case 'd': + { + double x[2], y[2]; + + memcpy(&x, p, sizeof(x)); + memcpy(&y, q, sizeof(y)); + return (x[0] == y[0]) && (x[1] == y[1]); + } + } + break; + } /* bytes object */ case 'c': return *p == *q; @@ -3106,7 +3200,7 @@ static int cmp_base(const char *p, const char *q, const Py_ssize_t *shape, const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, - char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q) + const char *fmt, struct unpacker *unpack_p, struct unpacker *unpack_q) { Py_ssize_t i; int equal; @@ -3129,7 +3223,7 @@ cmp_rec(const char *p, const char *q, Py_ssize_t ndim, const Py_ssize_t *shape, const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets, const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets, - char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q) + const char *fmt, struct unpacker *unpack_p, struct unpacker *unpack_q) { Py_ssize_t i; int equal; @@ -3168,7 +3262,7 @@ memory_richcompare(PyObject *v, PyObject *w, int op) Py_buffer *ww = NULL; struct unpacker *unpack_v = NULL; struct unpacker *unpack_w = NULL; - char vfmt, wfmt; + const char *vfmt, *wfmt; int equal = MV_COMPARE_NOT_IMPL; if (op != Py_EQ && op != Py_NE) @@ -3228,15 +3322,15 @@ memory_richcompare(PyObject *v, PyObject *w, int op) /* Use fast unpacking for identical primitive C type formats. */ if (get_native_fmtchar(&vfmt, vv->format) < 0) - vfmt = '_'; + vfmt = "_"; if (get_native_fmtchar(&wfmt, ww->format) < 0) - wfmt = '_'; - if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) { + wfmt = "_"; + if (strcmp(vfmt, "_") == 0 || strcmp(wfmt, "_") == 0 || strcmp(vfmt, wfmt) != 0) { /* Use struct module unpacking. NOTE: Even for equal format strings, memcmp() cannot be used for item comparison since it would give incorrect results in the case of NaNs or uninitialized padding bytes. */ - vfmt = '_'; + vfmt = "_"; unpack_v = struct_get_unpacker(vv->format, vv->itemsize); if (unpack_v == NULL) { equal = fix_struct_error_int(); @@ -3299,7 +3393,7 @@ memory_hash(PyObject *_self) Py_buffer *view = &self->view; char *mem = view->buf; Py_ssize_t ret; - char fmt; + const char *fmt; CHECK_RELEASED_INT(self); From 1e21cf6fee3830012e458c0fe5dbc6fcd45ace92 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 16:20:25 +0200 Subject: [PATCH 12/18] gh-148292: Remove shutdown() test in test_ssl.test_got_eof() (#149366) The shutdown() behavior depends too much on the operating system and it's unrelated to the got_eof_error change. --- Lib/test/test_ssl.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 97975db3bf49fb..f1f7a07701de16 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -5074,14 +5074,6 @@ def test_got_eof(self): sslsock.do_handshake() self.assertEqual(sslsock.pending(), 0) - try: - sslsock.shutdown(socket.SHUT_WR) - except OSError as exc: - self.assertEqual(exc.errno, errno.ENOTCONN) - else: - # On Windows and on OpenSSL 1.1.1, shutdown() doesn't - # raise an error - pass @unittest.skipUnless(has_tls_version('TLSv1_3') and ssl.HAS_PHA, From b8ebd078f90007d48fcab85effadb33769cd080c Mon Sep 17 00:00:00 2001 From: Kit Dallege Date: Mon, 4 May 2026 16:45:00 +0200 Subject: [PATCH 13/18] gh-137337: Clarify import statement namespace binding (GH-144607) It is not always in the local namespace. --- Doc/reference/simple_stmts.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 648e3a9bf54060..f8e54aa0a108c8 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -761,8 +761,9 @@ The basic import statement (no :keyword:`from` clause) is executed in two steps: #. find a module, loading and initializing it if necessary -#. define a name or names in the local namespace for the scope where - the :keyword:`import` statement occurs. +#. define a name or names in the current namespace for the scope where + the :keyword:`import` statement occurs, just as an assignment statement + would (including :keyword:`global` and :keyword:`nonlocal` semantics). When the statement contains multiple clauses (separated by commas) the two steps are carried out separately for each clause, just @@ -807,7 +808,7 @@ The :keyword:`from` form uses a slightly more complex process: #. if not, attempt to import a submodule with that name and then check the imported module again for that attribute #. if the attribute is not found, :exc:`ImportError` is raised. - #. otherwise, a reference to that value is stored in the local namespace, + #. otherwise, a reference to that value is stored in the current namespace, using the name in the :keyword:`!as` clause if it is present, otherwise using the attribute name From 5dd5c8b5a66af18904d4e015ce3120e2686ddb23 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 17:26:30 +0200 Subject: [PATCH 14/18] gh-148675: Remove F and D formats from array and memoryview (GH-149368) --- Doc/library/array.rst | 6 +-- Doc/whatsnew/3.15.rst | 6 +-- Lib/test/test_array.py | 20 +------- Lib/test/test_buffer.py | 12 ++--- Lib/test/test_memoryview.py | 6 +-- ...-05-04-16-26-33.gh-issue-148675.xZwXa6.rst | 2 + Modules/arraymodule.c | 21 ++------ Objects/memoryobject.c | 48 ------------------- 8 files changed, 17 insertions(+), 104 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst diff --git a/Doc/library/array.rst b/Doc/library/array.rst index 3cd107460596d1..02eb775f31effc 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -48,10 +48,6 @@ defined: +-----------+--------------------+-------------------+-----------------------+-------+ | ``'d'`` | double | float | 8 | | +-----------+--------------------+-------------------+-----------------------+-------+ -| ``'F'`` | float complex | complex | 8 | \(4) | -+-----------+--------------------+-------------------+-----------------------+-------+ -| ``'D'`` | double complex | complex | 16 | \(4) | -+-----------+--------------------+-------------------+-----------------------+-------+ | ``'Zf'`` | float complex | complex | 8 | \(4) | +-----------+--------------------+-------------------+-----------------------+-------+ | ``'Zd'`` | double complex | complex | 16 | \(4) | @@ -84,7 +80,7 @@ Notes: .. versionadded:: 3.15 (4) - Complex types (``F``, ``D``, ``Zf`` and ``Zd``) are available unconditionally, + Complex types (``Zf`` and ``Zd``) are available unconditionally, regardless on support for complex types (the Annex G of the C11 standard) by the C compiler. As specified in the C11 standard, each complex type is represented by a diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 2e408f258e2805..29576d15b3b181 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -671,8 +671,8 @@ Other language changes (Contributed by James Hilton-Balfe in :gh:`128335`.) * The class :class:`memoryview` now supports the :c:expr:`float complex` and - :c:expr:`double complex` C types: formatting characters ``'F'``/``'Zf'`` - and ``'D'``/``'Zd'`` respectively. + :c:expr:`double complex` C types: formatting characters ``'Zf'`` and ``'Zd'`` + respectively. (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Allow the *count* argument of :meth:`bytes.replace` to be a keyword. @@ -724,7 +724,7 @@ array ----- * Support the :c:expr:`float complex` and :c:expr:`double complex` C types: - formatting characters ``'F'``/``'Zf'`` and ``'D'``/``'Zd'`` respectively. + formatting characters ``'Zf'`` and ``'Zd'`` respectively. (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Support half-floats (16-bit IEEE 754 binary interchange format): formatting diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 54ecc886917dc7..f7fa56a6e4bfa0 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -33,7 +33,7 @@ def __init__(self, typecode, newarg=None): typecodes = ( 'u', 'w', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', - 'f', 'd', 'q', 'Q', 'F', 'D', 'e', 'Zf', 'Zd') + 'f', 'd', 'q', 'Q', 'e', 'Zf', 'Zd') class MiscTest(unittest.TestCase): @@ -210,14 +210,6 @@ def test_numbers(self): [9006104071832581.0, float('inf'), float('-inf'), -0.0]), (['d'], IEEE_754_DOUBLE_BE, '>dddd', [9006104071832581.0, float('inf'), float('-inf'), -0.0]), - (['F'], IEEE_754_FLOAT_COMPLEX_LE, 'FFFF', - [16711938.0j, float('inf'), complex('1-infj'), -0.0]), - (['D'], IEEE_754_DOUBLE_COMPLEX_LE, 'DDDD', - [9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]), (['Zf'], IEEE_754_FLOAT_COMPLEX_LE, 'ZfZfZfZf', @@ -1645,18 +1637,10 @@ def test_alloc_overflow(self): class ComplexFloatTest(CFPTest, unittest.TestCase): - typecode = 'F' - minitemsize = 8 - -class ComplexDoubleTest(CFPTest, unittest.TestCase): - typecode = 'D' - minitemsize = 16 - -class ComplexZfFloatTest(CFPTest, unittest.TestCase): typecode = 'Zf' minitemsize = 8 -class ComplexZdDoubleTest(CFPTest, unittest.TestCase): +class ComplexDoubleTest(CFPTest, unittest.TestCase): typecode = 'Zd' minitemsize = 16 diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 21a3d0b3422ad2..f08faa14b24c64 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -67,7 +67,7 @@ 'h':0, 'H':0, 'i':0, 'I':0, 'l':0, 'L':0, 'n':0, 'N':0, 'e':0, 'f':0, 'd':0, 'P':0, - 'F':0, 'D':0, 'Zf':0, 'Zd':0, + 'Zf':0, 'Zd':0, } # NumPy does not have 'n' or 'N': @@ -94,8 +94,6 @@ 'q':(-(1<<63), 1<<63), 'Q':(0, 1<<64), 'e':(-65519, 65520), 'f':(-(1<<63), 1<<63), 'd':(-(1<<1023), 1<<1023), - 'F':(-(1<<63), 1<<63), - 'D':(-(1<<1023), 1<<1023), 'Zf':(-(1<<63), 1<<63), 'Zd':(-(1<<1023), 1<<1023), } @@ -112,9 +110,9 @@ def native_type_range(fmt): lh = (-(1<<63), 1<<63) elif fmt == 'd': lh = (-(1<<1023), 1<<1023) - elif fmt in ('F', 'Zf'): + elif fmt == 'Zf': lh = (-(1<<63), 1<<63) - elif fmt in ('D', 'Zd'): + elif fmt == 'Zd': lh = (-(1<<1023), 1<<1023) else: for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7): @@ -184,7 +182,7 @@ def randrange_fmt(mode, char, obj): if char in 'efd': x = struct.pack(char, x) x = struct.unpack(char, x)[0] - if char in ('F', 'D', 'Zf', 'Zd'): + if char in ('Zf', 'Zd'): y = randrange(*fmtdict[mode][char]) x = complex(x, y) x = struct.pack(char, x) @@ -3055,7 +3053,7 @@ def test_memoryview_assign(self): continue m2 = m1.cast(fmt) lo, hi = _range - if fmt in ("d", "f", "D", "F", "Zd", "Zf"): + if fmt in ("d", "f", "Zd", "Zf"): lo, hi = -2**1024, 2**1024 if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers self.assertRaises(ValueError, m2.__setitem__, 0, lo-1) diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index f777ba583c5c06..f71b6f53486509 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -637,7 +637,7 @@ def check_equal(view, is_equal): check_equal(m, True) # Test complex formats - for complex_format in ('F', 'D', 'Zf', 'Zd'): + for complex_format in ('Zf', 'Zd'): with self.subTest(format=complex_format): data = struct.pack(complex_format * 3, 1.0, 2.0, float('nan')) m = memoryview(data).cast(complex_format) @@ -719,10 +719,6 @@ def test_half_float(self): def test_complex_types(self): float_complex_data = struct.pack('FFF', 0.0, -1.5j, 1+2j) double_complex_data = struct.pack('DDD', 0.0, -1.5j, 1+2j) - float_complex_view = memoryview(float_complex_data).cast('F') - double_complex_view = memoryview(double_complex_data).cast('D') - self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes) - self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist()) float_complex_view = memoryview(float_complex_data).cast('Zf') double_complex_view = memoryview(double_complex_data).cast('Zd') self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes) diff --git a/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst b/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst new file mode 100644 index 00000000000000..6ba2e7aabf9ec8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst @@ -0,0 +1,2 @@ +Remove ``F`` and ``D`` formats from :mod:`array` and :class:`memoryview`. +Patch by Victor Stinner. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 56a2a98fe42731..a8347123e6496a 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -782,8 +782,6 @@ static const struct arraydescr descriptors[] = { {"e", sizeof(short), e_getitem, e_setitem, NULL, 0, 0}, {"f", sizeof(float), f_getitem, f_setitem, NULL, 0, 0}, {"d", sizeof(double), d_getitem, d_setitem, NULL, 0, 0}, - {"F", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, - {"D", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, {"Zf", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, {"Zd", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, {NULL, 0, 0, 0, 0, 0, 0} /* Sentinel */ @@ -1612,9 +1610,7 @@ array_array_byteswap_impl(arrayobject *self) } break; case 8: - if (strcmp(self->ob_descr->typecode, "F") != 0 - && strcmp(self->ob_descr->typecode, "Zf") != 0) - { + if (strcmp(self->ob_descr->typecode, "Zf") != 0) { for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char p0 = p[0]; char p1 = p[1]; @@ -1648,8 +1644,7 @@ array_array_byteswap_impl(arrayobject *self) } break; case 16: - assert(strcmp(self->ob_descr->typecode, "D") == 0 - || strcmp(self->ob_descr->typecode, "Zd") == 0); + assert(strcmp(self->ob_descr->typecode, "Zd") == 0); for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char t0 = p[0]; char t1 = p[1]; @@ -2159,14 +2154,6 @@ typecode_to_mformat_code(const char *typecode) case 'd': return _PY_FLOAT_BIG_ENDIAN ? IEEE_754_DOUBLE_BE : IEEE_754_DOUBLE_LE; - case 'F': - return _PY_FLOAT_BIG_ENDIAN ? \ - IEEE_754_FLOAT_COMPLEX_BE : IEEE_754_FLOAT_COMPLEX_LE; - - case 'D': - return _PY_FLOAT_BIG_ENDIAN ? \ - IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE; - case 'Z': { switch (typecode[1]) { case 'f': @@ -3167,7 +3154,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } Py_XDECREF(it); PyErr_SetString(PyExc_ValueError, - "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, e, f, d, F, D, Zf or Zd)"); + "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, e, f, d, Zf or Zd)"); return NULL; } @@ -3205,8 +3192,6 @@ The following type codes are defined:\n\ 'e' 16-bit IEEE floats 2\n\ 'f' floating-point 4\n\ 'd' floating-point 8\n\ - 'F' float complex 8\n\ - 'D' double complex 16\n\ 'Zf' float complex 8\n\ 'Zd' double complex 16\n\ \n\ diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 2c2f85ebf6acc0..900db864621a84 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1217,8 +1217,6 @@ get_native_fmtchar(const char **result, const char *fmt) case 'f': size = sizeof(float); break; case 'd': size = sizeof(double); break; case 'e': size = sizeof(float) / 2; break; - case 'F': size = 2*sizeof(float); break; - case 'D': size = 2*sizeof(double); break; case '?': size = sizeof(_Bool); break; case 'P': size = sizeof(void *); break; case 'Z': { @@ -1284,8 +1282,6 @@ get_native_fmtstr(const char *fmt) case 'f': RETURN("f"); case 'd': RETURN("d"); case 'e': RETURN("e"); - case 'F': RETURN("F"); - case 'D': RETURN("D"); case 'Z': { switch (fmt[1]) { case 'f': RETURN("Zf"); @@ -1865,16 +1861,6 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt) case 'e': d[0] = PyFloat_Unpack2(ptr, endian); goto convert_double; /* complexes */ - case 'F': - d[0] = PyFloat_Unpack4(ptr, endian); - d[1] = PyFloat_Unpack4(ptr + sizeof(float), endian); - goto convert_double_complex; - - case 'D': - d[0] = PyFloat_Unpack8(ptr, endian); - d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian); - goto convert_double_complex; - case 'Z': { switch (fmt[1]) { case 'f': @@ -2055,24 +2041,6 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt break; /* complexes */ - case 'F': case 'D': - c = PyComplex_AsCComplex(item); - if (c.real == -1.0 && PyErr_Occurred()) { - goto err_occurred; - } - CHECK_RELEASED_INT_AGAIN(self); - if (fmt[0] == 'D') { - double x[2] = {c.real, c.imag}; - - memcpy(ptr, &x, sizeof(x)); - } - else { - float x[2] = {(float)c.real, (float)c.imag}; - - memcpy(ptr, &x, sizeof(x)); - } - break; - case 'Z': { switch (fmt[1]) { case 'f': case 'd': @@ -3138,22 +3106,6 @@ unpack_cmp(const char *p, const char *q, const char *fmt, } /* complexes */ - case 'F': - { - float x[2], y[2]; - - memcpy(&x, p, sizeof(x)); - memcpy(&y, q, sizeof(y)); - return (x[0] == y[0]) && (x[1] == y[1]); - } - case 'D': - { - double x[2], y[2]; - - memcpy(&x, p, sizeof(x)); - memcpy(&y, q, sizeof(y)); - return (x[0] == y[0]) && (x[1] == y[1]); - } case 'Z': { switch (fmt[1]) { case 'f': From 6ca5cdba185aeb3b7f72ae0dd61b6a9685d8c416 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 4 May 2026 17:32:17 +0200 Subject: [PATCH 15/18] gh-149225: Expose Py_CriticalSection in Stable ABI (GH-149227) --- Doc/c-api/synchronization.rst | 61 ++++++++++-- Doc/data/stable_abi.dat | 10 ++ Doc/whatsnew/3.15.rst | 5 + Include/cpython/critical_section.h | 93 ++----------------- Include/critical_section.h | 85 +++++++++++++++++ Lib/test/test_cext/extension.c | 4 + Lib/test/test_stable_abi_ctypes.py | 4 + ...-05-01-14-49-09.gh-issue-149225.IdAYPZ.rst | 2 + Misc/stable_abi.toml | 22 +++++ PC/python3dll.c | 4 + 10 files changed, 195 insertions(+), 95 deletions(-) create mode 100644 Misc/NEWS.d/next/C_API/2026-05-01-14-49-09.gh-issue-149225.IdAYPZ.rst diff --git a/Doc/c-api/synchronization.rst b/Doc/c-api/synchronization.rst index 53c9faeae35464..7e9894f4d692d6 100644 --- a/Doc/c-api/synchronization.rst +++ b/Doc/c-api/synchronization.rst @@ -84,11 +84,6 @@ there is no :c:type:`PyObject` -- for example, when working with a C type that does not extend or wrap :c:type:`PyObject` but still needs to call into the C API in a manner that might lead to deadlocks. -The functions and structs used by the macros are exposed for cases -where C macros are not available. They should only be used as in the -given macro expansions. Note that the sizes and contents of the structures may -change in future Python versions. - .. note:: Operations that need to lock two objects at once must use @@ -114,12 +109,15 @@ section API avoids potential deadlocks due to reentrancy and lock ordering by allowing the runtime to temporarily suspend the critical section if the code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. +.. _critical-section-macros: + .. c:macro:: Py_BEGIN_CRITICAL_SECTION(op) Acquires the per-object lock for the object *op* and begins a critical section. - In the free-threaded build, this macro expands to:: + In the free-threaded build, and when building for the + :ref:`Stable ABI `, this macro expands to:: { PyCriticalSection _py_cs; @@ -150,7 +148,8 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. Ends the critical section and releases the per-object lock. - In the free-threaded build, this macro expands to:: + In the free-threaded build, and when building for the + :ref:`Stable ABI `, this macro expands to:: PyCriticalSection_End(&_py_cs); } @@ -179,7 +178,8 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. Locks the mutexes *m1* and *m2* and begins a critical section. - In the free-threaded build, this macro expands to:: + In the free-threaded build, and when building for the + :ref:`Stable ABI `, this macro expands to:: { PyCriticalSection2 _py_cs2; @@ -196,7 +196,8 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. Ends the critical section and releases the per-object locks. - In the free-threaded build, this macro expands to:: + In the free-threaded build, and when building for the + :ref:`Stable ABI `, this macro expands to:: PyCriticalSection2_End(&_py_cs2); } @@ -205,6 +206,48 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`. .. versionadded:: 3.13 +Low-level critical section API +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following functions and structs are exposed for cases where C macros +are not available. + +.. c:function:: void PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op) + void PyCriticalSection_End(PyCriticalSection *c) + void PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b) + void PyCriticalSection2_End(PyCriticalSection2 *c); + + To be used only as in the macro expansions + listed :ref:`earlier in this section `. + + In non-:term:`free-threaded ` builds of CPython, these + functions do nothing. + + .. versionadded:: 3.13 + +.. c:type:: PyCriticalSection + PyCriticalSection2 + + To be used only as in the macro expansions + listed :ref:`earlier in this section `. + Note that the contents of the structures are private and their meaning may + change in future Python versions. + + .. versionadded:: 3.13 + +.. c:function:: void PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m); + void PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2); + + .. (These need to be in a separate section without a Stable ABI anotation.) + + To be used only as in the macro expansions + listed :ref:`earlier in this section `. + + In non-:term:`free-threaded ` builds of CPython, these + functions do nothing. + + .. versionadded:: 3.14 + Legacy locking APIs ------------------- diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 2ef2bccf2b7728..49277b57b877d4 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -129,6 +129,12 @@ func,PyComplex_FromDoubles,3.2,, func,PyComplex_ImagAsDouble,3.2,, func,PyComplex_RealAsDouble,3.2,, data,PyComplex_Type,3.2,, +type,PyCriticalSection,3.15,,full-abi +type,PyCriticalSection2,3.15,,full-abi +func,PyCriticalSection2_Begin,3.15,, +func,PyCriticalSection2_End,3.15,, +func,PyCriticalSection_Begin,3.15,, +func,PyCriticalSection_End,3.15,, func,PyDescr_NewClassMethod,3.2,, func,PyDescr_NewGetSet,3.2,, func,PyDescr_NewMember,3.2,, @@ -906,6 +912,8 @@ macro,Py_AUDIT_READ,3.12,, func,Py_AddPendingCall,3.2,, func,Py_AtExit,3.2,, macro,Py_BEGIN_ALLOW_THREADS,3.2,, +macro,Py_BEGIN_CRITICAL_SECTION,3.15,, +macro,Py_BEGIN_CRITICAL_SECTION2,3.15,, macro,Py_BLOCK_THREADS,3.2,, func,Py_BuildValue,3.2,, func,Py_BytesMain,3.8,, @@ -913,6 +921,8 @@ func,Py_CompileString,3.2,, func,Py_DecRef,3.2,, func,Py_DecodeLocale,3.7,, macro,Py_END_ALLOW_THREADS,3.2,, +macro,Py_END_CRITICAL_SECTION,3.15,, +macro,Py_END_CRITICAL_SECTION2,3.15,, func,Py_EncodeLocale,3.7,, func,Py_EndInterpreter,3.2,, func,Py_EnterRecursiveCall,3.9,, diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 29576d15b3b181..3baae534041446 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -2098,6 +2098,11 @@ New features (Contributed by Victor Stinner in :gh:`129813`.) +* :c:type:`PyCriticalSection` and related functions are added to the Stable + ABI. + + (Contributed in :gh:`149227`.) + * Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating a module from a *spec* and *initfunc*. (Contributed by Itamar Oren in :gh:`116146`.) diff --git a/Include/cpython/critical_section.h b/Include/cpython/critical_section.h index 4fc46fefb93a24..bcba32da412f32 100644 --- a/Include/cpython/critical_section.h +++ b/Include/cpython/critical_section.h @@ -2,15 +2,6 @@ # error "this header file must not be included directly" #endif -// Python critical sections -// -// Conceptually, critical sections are a deadlock avoidance layer on top of -// per-object locks. These helpers, in combination with those locks, replace -// our usage of the global interpreter lock to provide thread-safety for -// otherwise thread-unsafe objects, such as dict. -// -// NOTE: These APIs are no-ops in non-free-threaded builds. -// // Straightforward per-object locking could introduce deadlocks that were not // present when running with the GIL. Threads may hold locks for multiple // objects simultaneously because Python operations can nest. If threads were @@ -43,52 +34,19 @@ // `_PyThreadState_Attach()`, it resumes the top-most (i.e., most recent) // critical section by reacquiring the associated lock or locks. See // `_PyCriticalSection_Resume()`. -// -// NOTE: Only the top-most critical section is guaranteed to be active. -// Operations that need to lock two objects at once must use -// `Py_BEGIN_CRITICAL_SECTION2()`. You *CANNOT* use nested critical sections -// to lock more than one object at once, because the inner critical section -// may suspend the outer critical sections. This API does not provide a way -// to lock more than two objects at once (though it could be added later -// if actually needed). -// -// NOTE: Critical sections implicitly behave like reentrant locks because -// attempting to acquire the same lock will suspend any outer (earlier) -// critical sections. However, they are less efficient for this use case than -// purposefully designed reentrant locks. -// -// Example usage: -// Py_BEGIN_CRITICAL_SECTION(op); -// ... -// Py_END_CRITICAL_SECTION(); -// -// To lock two objects at once: -// Py_BEGIN_CRITICAL_SECTION2(op1, op2); -// ... -// Py_END_CRITICAL_SECTION2(); - -typedef struct PyCriticalSection PyCriticalSection; -typedef struct PyCriticalSection2 PyCriticalSection2; - -PyAPI_FUNC(void) -PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op); PyAPI_FUNC(void) PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m); -PyAPI_FUNC(void) -PyCriticalSection_End(PyCriticalSection *c); - -PyAPI_FUNC(void) -PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b); - PyAPI_FUNC(void) PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2); -PyAPI_FUNC(void) -PyCriticalSection2_End(PyCriticalSection2 *c); - #ifndef Py_GIL_DISABLED +#undef Py_BEGIN_CRITICAL_SECTION +#undef Py_END_CRITICAL_SECTION +#undef Py_BEGIN_CRITICAL_SECTION2 +#undef Py_END_CRITICAL_SECTION2 + # define Py_BEGIN_CRITICAL_SECTION(op) \ { # define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \ @@ -101,54 +59,17 @@ PyCriticalSection2_End(PyCriticalSection2 *c); { # define Py_END_CRITICAL_SECTION2() \ } -#else /* !Py_GIL_DISABLED */ - -// NOTE: the contents of this struct are private and may change betweeen -// Python releases without a deprecation period. -struct PyCriticalSection { - // Tagged pointer to an outer active critical section (or 0). - uintptr_t _cs_prev; - - // Mutex used to protect critical section - PyMutex *_cs_mutex; -}; - -// A critical section protected by two mutexes. Use -// Py_BEGIN_CRITICAL_SECTION2 and Py_END_CRITICAL_SECTION2. -// NOTE: the contents of this struct are private and may change betweeen -// Python releases without a deprecation period. -struct PyCriticalSection2 { - PyCriticalSection _cs_base; - PyMutex *_cs_mutex2; -}; - -# define Py_BEGIN_CRITICAL_SECTION(op) \ - { \ - PyCriticalSection _py_cs; \ - PyCriticalSection_Begin(&_py_cs, _PyObject_CAST(op)) +#else /* !Py_GIL_DISABLED */ # define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \ { \ PyCriticalSection _py_cs; \ PyCriticalSection_BeginMutex(&_py_cs, mutex) -# define Py_END_CRITICAL_SECTION() \ - PyCriticalSection_End(&_py_cs); \ - } - -# define Py_BEGIN_CRITICAL_SECTION2(a, b) \ - { \ - PyCriticalSection2 _py_cs2; \ - PyCriticalSection2_Begin(&_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b)) - # define Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2) \ { \ PyCriticalSection2 _py_cs2; \ PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2) -# define Py_END_CRITICAL_SECTION2() \ - PyCriticalSection2_End(&_py_cs2); \ - } - -#endif +#endif /* !Py_GIL_DISABLED */ diff --git a/Include/critical_section.h b/Include/critical_section.h index 3b37615a8b17e2..732bfab7ecf234 100644 --- a/Include/critical_section.h +++ b/Include/critical_section.h @@ -4,6 +4,91 @@ extern "C" { #endif +// Python critical sections +// +// Conceptually, critical sections are a deadlock avoidance layer on top of +// per-object locks. These helpers, in combination with those locks, replace +// our usage of the global interpreter lock to provide thread-safety for +// otherwise thread-unsafe objects, such as dict. +// +// NOTE: These APIs are no-ops in non-free-threaded builds. +// +// NOTE: Only the top-most critical section is guaranteed to be active. +// Operations that need to lock two objects at once must use +// `Py_BEGIN_CRITICAL_SECTION2()`. You *CANNOT* use nested critical sections +// to lock more than one object at once, because the inner critical section +// may suspend the outer critical sections. This API does not provide a way +// to lock more than two objects at once (though it could be added later +// if actually needed). +// +// NOTE: Critical sections implicitly behave like reentrant locks because +// attempting to acquire the same lock will suspend any outer (earlier) +// critical sections. However, they are less efficient for this use case than +// purposefully designed reentrant locks. +// +// Example usage: +// Py_BEGIN_CRITICAL_SECTION(op); +// ... +// Py_END_CRITICAL_SECTION(); +// +// To lock two objects at once: +// Py_BEGIN_CRITICAL_SECTION2(op1, op2); +// ... +// Py_END_CRITICAL_SECTION2(); + +// NOTE: the contents of this struct are private and their meaning may +// change betweeen Python releases without a deprecation period. +typedef struct PyCriticalSection { + // Tagged pointer to an outer active critical section (or 0). + uintptr_t _cs_prev; + + // Mutex used to protect critical section + struct PyMutex *_cs_mutex; +} PyCriticalSection; + +// A critical section protected by two mutexes. Use +// Py_BEGIN_CRITICAL_SECTION2 and Py_END_CRITICAL_SECTION2. +// NOTE: the contents of this struct are private and may change betweeen +// Python releases without a deprecation period. +typedef struct PyCriticalSection2 { + PyCriticalSection _cs_base; + + struct PyMutex *_cs_mutex2; +} PyCriticalSection2; + +PyAPI_FUNC(void) +PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op); + +PyAPI_FUNC(void) +PyCriticalSection_End(PyCriticalSection *c); + +PyAPI_FUNC(void) +PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b); + +PyAPI_FUNC(void) +PyCriticalSection2_End(PyCriticalSection2 *c); + +// These are definitions for the stable ABI. For GIL-ful builds they're +// conditionally redefined as no-ops in cpython/critical_section.h. + +# define Py_BEGIN_CRITICAL_SECTION(op) \ + { \ + PyCriticalSection _py_cs; \ + PyCriticalSection_Begin(&_py_cs, _PyObject_CAST(op)) + +# define Py_END_CRITICAL_SECTION() \ + PyCriticalSection_End(&_py_cs); \ + } + +# define Py_BEGIN_CRITICAL_SECTION2(a, b) \ + { \ + PyCriticalSection2 _py_cs2; \ + PyCriticalSection2_Begin(&_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b)) + +# define Py_END_CRITICAL_SECTION2() \ + PyCriticalSection2_End(&_py_cs2); \ + } + #ifndef Py_LIMITED_API # define Py_CPYTHON_CRITICAL_SECTION_H # include "cpython/critical_section.h" diff --git a/Lib/test/test_cext/extension.c b/Lib/test/test_cext/extension.c index a880cb82811f78..46d00f3845eaa6 100644 --- a/Lib/test/test_cext/extension.c +++ b/Lib/test/test_cext/extension.c @@ -99,6 +99,10 @@ _testcext_exec(PyObject *module) obj = NULL; Py_CLEAR(obj); + // Test that Py_BEGIN_CRITICAL_SECTION is available + Py_BEGIN_CRITICAL_SECTION(module); + Py_END_CRITICAL_SECTION(); + return 0; } diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 5dae5dfccac5d3..7b348ff298a4b2 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -134,6 +134,10 @@ def test_windows_feature_macros(self): "PyComplex_ImagAsDouble", "PyComplex_RealAsDouble", "PyComplex_Type", + "PyCriticalSection2_Begin", + "PyCriticalSection2_End", + "PyCriticalSection_Begin", + "PyCriticalSection_End", "PyDescr_NewClassMethod", "PyDescr_NewGetSet", "PyDescr_NewMember", diff --git a/Misc/NEWS.d/next/C_API/2026-05-01-14-49-09.gh-issue-149225.IdAYPZ.rst b/Misc/NEWS.d/next/C_API/2026-05-01-14-49-09.gh-issue-149225.IdAYPZ.rst new file mode 100644 index 00000000000000..98d716ab5fa764 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-05-01-14-49-09.gh-issue-149225.IdAYPZ.rst @@ -0,0 +1,2 @@ +:c:type:`PyCriticalSection` and related functions are added to the Stable +ABI. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index e6c63227d20446..bd3ea545825809 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2689,6 +2689,28 @@ added = '3.15' [function.PyType_GetModuleByToken_DuringGC] added = '3.15' +[function.PyCriticalSection_Begin] + added = '3.15' +[function.PyCriticalSection_End] + added = '3.15' +[struct.PyCriticalSection] + added = '3.15' + struct_abi_kind = 'full-abi' +[macro.Py_BEGIN_CRITICAL_SECTION] + added = '3.15' +[macro.Py_END_CRITICAL_SECTION] + added = '3.15' +[function.PyCriticalSection2_Begin] + added = '3.15' +[function.PyCriticalSection2_End] + added = '3.15' +[struct.PyCriticalSection2] + added = '3.15' + struct_abi_kind = 'full-abi' +[macro.Py_BEGIN_CRITICAL_SECTION2] + added = '3.15' +[macro.Py_END_CRITICAL_SECTION2] + added = '3.15' # PEP 757 import/export API. [function.PyLong_GetNativeLayout] diff --git a/PC/python3dll.c b/PC/python3dll.c index 6b9ef0a4164c16..3303fccf0261af 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -174,6 +174,10 @@ EXPORT_FUNC(PyCodec_XMLCharRefReplaceErrors) EXPORT_FUNC(PyComplex_FromDoubles) EXPORT_FUNC(PyComplex_ImagAsDouble) EXPORT_FUNC(PyComplex_RealAsDouble) +EXPORT_FUNC(PyCriticalSection2_Begin) +EXPORT_FUNC(PyCriticalSection2_End) +EXPORT_FUNC(PyCriticalSection_Begin) +EXPORT_FUNC(PyCriticalSection_End) EXPORT_FUNC(PyDescr_NewClassMethod) EXPORT_FUNC(PyDescr_NewGetSet) EXPORT_FUNC(PyDescr_NewMember) From 952784af4793e6f819bfecc6e0a50676c7256e3a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 18:09:57 +0200 Subject: [PATCH 16/18] gh-137030: Fix YIELD_VALUE bytecode assertion (#149184) Co-authored-by: Mark Shannon --- Include/internal/pycore_code.h | 3 ++- Include/internal/pycore_opcode_metadata.h | 2 +- Include/internal/pycore_uop_metadata.h | 2 +- Modules/_testinternalcapi/test_cases.c.h | 28 +++++++++++------------ Python/bytecodes.c | 13 +++++------ Python/executor_cases.c.h | 13 +++++------ Python/generated_cases.c.h | 28 +++++++++++------------ 7 files changed, 44 insertions(+), 45 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 4584f1bde7974e..5b1fddbe15b98b 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -539,7 +539,8 @@ typedef struct { PyAPI_FUNC(int) _Py_Instrument(PyCodeObject *co, PyInterpreterState *interp); -extern _Py_CODEUNIT _Py_GetBaseCodeUnit(PyCodeObject *code, int offset); +// Export for '_testinternalcapi' shared extension +PyAPI_FUNC(_Py_CODEUNIT) _Py_GetBaseCodeUnit(PyCodeObject *code, int offset); extern int _PyInstruction_GetLength(PyCodeObject *code, int offset); diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 8c4134061de94c..3f0cdb0dd0dd53 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1335,7 +1335,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG }, [WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, + [YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG }, [JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index d6ab67c2e2e86e..cd1e95ffb2b141 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -168,7 +168,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_GET_ANEXT] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GET_AWAITABLE] = HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_SEND_GEN_FRAME] = HAS_ARG_FLAG | HAS_EXIT_FLAG, - [_YIELD_VALUE] = HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG, + [_YIELD_VALUE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG, [_POP_EXCEPT] = HAS_ESCAPES_FLAG, [_LOAD_COMMON_CONSTANT] = HAS_ARG_FLAG, [_LOAD_BUILD_CLASS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, diff --git a/Modules/_testinternalcapi/test_cases.c.h b/Modules/_testinternalcapi/test_cases.c.h index dac46a3e22afa9..c65767e42da2e9 100644 --- a/Modules/_testinternalcapi/test_cases.c.h +++ b/Modules/_testinternalcapi/test_cases.c.h @@ -7890,6 +7890,7 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); + opcode = INSTRUMENTED_YIELD_VALUE; _PyStackRef val; _PyStackRef value; _PyStackRef retval; @@ -7935,13 +7936,12 @@ ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); @@ -12913,6 +12913,7 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(YIELD_VALUE); + opcode = YIELD_VALUE; _PyStackRef value; _PyStackRef retval; // _MAKE_HEAP_SAFE @@ -12941,13 +12942,12 @@ ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0277a94ab36632..3f33b6be8679f9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1770,13 +1770,12 @@ dummy_func( FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); /* We don't know which of these is relevant here, so keep them equal */ assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif RELOAD_STACK(); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b670ff3e766155..a82bec4c9fde36 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -8839,13 +8839,12 @@ ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index bd2cf1c9cb19e5..7fea3ddfc6f559 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -7889,6 +7889,7 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(INSTRUMENTED_YIELD_VALUE); + opcode = INSTRUMENTED_YIELD_VALUE; _PyStackRef val; _PyStackRef value; _PyStackRef retval; @@ -7934,13 +7935,12 @@ ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); @@ -12910,6 +12910,7 @@ frame->instr_ptr = next_instr; next_instr += 1; INSTRUCTION_STATS(YIELD_VALUE); + opcode = YIELD_VALUE; _PyStackRef value; _PyStackRef retval; // _MAKE_HEAP_SAFE @@ -12938,13 +12939,12 @@ ((_PyThreadStateImpl *)tstate)->generator_return_kind = GENERATOR_YIELD; FT_ATOMIC_STORE_INT8_RELEASE(gen->gi_frame_state, FRAME_SUSPENDED + oparg); assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER); - #if TIER_ONE - assert(frame->instr_ptr->op.code == INSTRUMENTED_LINE || - frame->instr_ptr->op.code == INSTRUMENTED_INSTRUCTION || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == SEND || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == FOR_ITER || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == INTERPRETER_EXIT || - _PyOpcode_Deopt[frame->instr_ptr->op.code] == ENTER_EXECUTOR); + #if TIER_ONE && defined(Py_DEBUG) + if (!PyStackRef_IsNone(frame->f_executable)) { + int i = frame->instr_ptr - _PyFrame_GetBytecode(frame); + int opcode = _Py_GetBaseCodeUnit(_PyFrame_GetCode(frame), i).op.code; + assert(opcode == SEND || opcode == FOR_ITER); + } #endif stack_pointer = _PyFrame_GetStackPointer(frame); LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND); From 9846407eaf385917d134ef5e3700c57c59f67684 Mon Sep 17 00:00:00 2001 From: Neko Asakura Date: Tue, 5 May 2026 00:29:10 +0800 Subject: [PATCH 17/18] gh-143732: add specialization for `FOR_ITER` (GH-148745) --- Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_uop_ids.h | 2277 +++++++++-------- Include/internal/pycore_uop_metadata.h | 36 + Lib/test/test_capi/test_opt.py | 129 +- Lib/test/test_generated_cases.py | 16 +- Python/bytecodes.c | 27 +- Python/executor_cases.c.h | 146 ++ Python/optimizer.c | 1 + Python/optimizer_bytecodes.c | 22 + Python/optimizer_cases.c.h | 34 + Python/record_functions.c.h | 25 +- .../record_function_generator.py | 28 +- 12 files changed, 1569 insertions(+), 1176 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 3f0cdb0dd0dd53..b82ad991d539d5 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1190,7 +1190,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, + [FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_RECORDS_VALUE_FLAG }, [FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG }, [FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, @@ -1438,7 +1438,7 @@ _PyOpcode_macro_expansion[256] = { [EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { _EXIT_INIT_CHECK, OPARG_SIMPLE, 0 } } }, [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, OPARG_SIMPLE, 0 } } }, [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { _FORMAT_WITH_SPEC, OPARG_SIMPLE, 0 } } }, - [FOR_ITER] = { .nuops = 1, .uops = { { _FOR_ITER, OPARG_REPLACED, 0 } } }, + [FOR_ITER] = { .nuops = 2, .uops = { { _RECORD_NOS_TYPE, OPARG_SIMPLE, 0 }, { _FOR_ITER, OPARG_REPLACED, 0 } } }, [FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS_GEN_FUNC, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } }, [FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } }, [FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index d1919b9f8df362..190d4aba7574fe 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -231,19 +231,20 @@ extern "C" { #define _GUARD_TOS_TUPLE 492 #define _GUARD_TOS_UNICODE 493 #define _GUARD_TYPE 494 -#define _GUARD_TYPE_VERSION 495 -#define _GUARD_TYPE_VERSION_LOCKED 496 -#define _HANDLE_PENDING_AND_DEOPT 497 +#define _GUARD_TYPE_ITER 495 +#define _GUARD_TYPE_VERSION 496 +#define _GUARD_TYPE_VERSION_LOCKED 497 +#define _HANDLE_PENDING_AND_DEOPT 498 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 498 -#define _INIT_CALL_PY_EXACT_ARGS 499 -#define _INIT_CALL_PY_EXACT_ARGS_0 500 -#define _INIT_CALL_PY_EXACT_ARGS_1 501 -#define _INIT_CALL_PY_EXACT_ARGS_2 502 -#define _INIT_CALL_PY_EXACT_ARGS_3 503 -#define _INIT_CALL_PY_EXACT_ARGS_4 504 -#define _INSERT_NULL 505 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 499 +#define _INIT_CALL_PY_EXACT_ARGS 500 +#define _INIT_CALL_PY_EXACT_ARGS_0 501 +#define _INIT_CALL_PY_EXACT_ARGS_1 502 +#define _INIT_CALL_PY_EXACT_ARGS_2 503 +#define _INIT_CALL_PY_EXACT_ARGS_3 504 +#define _INIT_CALL_PY_EXACT_ARGS_4 505 +#define _INSERT_NULL 506 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -253,1167 +254,1173 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 506 -#define _IS_OP 507 -#define _ITER_CHECK_LIST 508 -#define _ITER_CHECK_RANGE 509 -#define _ITER_CHECK_TUPLE 510 -#define _ITER_JUMP_LIST 511 -#define _ITER_JUMP_RANGE 512 -#define _ITER_JUMP_TUPLE 513 -#define _ITER_NEXT_LIST 514 -#define _ITER_NEXT_LIST_TIER_TWO 515 -#define _ITER_NEXT_RANGE 516 -#define _ITER_NEXT_TUPLE 517 +#define _IS_NONE 507 +#define _IS_OP 508 +#define _ITER_CHECK_LIST 509 +#define _ITER_CHECK_RANGE 510 +#define _ITER_CHECK_TUPLE 511 +#define _ITER_JUMP_LIST 512 +#define _ITER_JUMP_RANGE 513 +#define _ITER_JUMP_TUPLE 514 +#define _ITER_NEXT_INLINE 515 +#define _ITER_NEXT_LIST 516 +#define _ITER_NEXT_LIST_TIER_TWO 517 +#define _ITER_NEXT_RANGE 518 +#define _ITER_NEXT_TUPLE 519 #define _JUMP_BACKWARD_NO_INTERRUPT JUMP_BACKWARD_NO_INTERRUPT -#define _JUMP_TO_TOP 518 +#define _JUMP_TO_TOP 520 #define _LIST_APPEND LIST_APPEND -#define _LIST_EXTEND 519 -#define _LOAD_ATTR 520 -#define _LOAD_ATTR_CLASS 521 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME 522 -#define _LOAD_ATTR_INSTANCE_VALUE 523 -#define _LOAD_ATTR_METHOD_LAZY_DICT 524 -#define _LOAD_ATTR_METHOD_NO_DICT 525 -#define _LOAD_ATTR_METHOD_WITH_VALUES 526 -#define _LOAD_ATTR_MODULE 527 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 528 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 529 -#define _LOAD_ATTR_PROPERTY_FRAME 530 -#define _LOAD_ATTR_SLOT 531 -#define _LOAD_ATTR_WITH_HINT 532 +#define _LIST_EXTEND 521 +#define _LOAD_ATTR 522 +#define _LOAD_ATTR_CLASS 523 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME 524 +#define _LOAD_ATTR_INSTANCE_VALUE 525 +#define _LOAD_ATTR_METHOD_LAZY_DICT 526 +#define _LOAD_ATTR_METHOD_NO_DICT 527 +#define _LOAD_ATTR_METHOD_WITH_VALUES 528 +#define _LOAD_ATTR_MODULE 529 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 530 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 531 +#define _LOAD_ATTR_PROPERTY_FRAME 532 +#define _LOAD_ATTR_SLOT 533 +#define _LOAD_ATTR_WITH_HINT 534 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 533 +#define _LOAD_BYTECODE 535 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST -#define _LOAD_CONST_INLINE 534 -#define _LOAD_CONST_INLINE_BORROW 535 +#define _LOAD_CONST_INLINE 536 +#define _LOAD_CONST_INLINE_BORROW 537 #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 536 -#define _LOAD_FAST_0 537 -#define _LOAD_FAST_1 538 -#define _LOAD_FAST_2 539 -#define _LOAD_FAST_3 540 -#define _LOAD_FAST_4 541 -#define _LOAD_FAST_5 542 -#define _LOAD_FAST_6 543 -#define _LOAD_FAST_7 544 +#define _LOAD_FAST 538 +#define _LOAD_FAST_0 539 +#define _LOAD_FAST_1 540 +#define _LOAD_FAST_2 541 +#define _LOAD_FAST_3 542 +#define _LOAD_FAST_4 543 +#define _LOAD_FAST_5 544 +#define _LOAD_FAST_6 545 +#define _LOAD_FAST_7 546 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 545 -#define _LOAD_FAST_BORROW_0 546 -#define _LOAD_FAST_BORROW_1 547 -#define _LOAD_FAST_BORROW_2 548 -#define _LOAD_FAST_BORROW_3 549 -#define _LOAD_FAST_BORROW_4 550 -#define _LOAD_FAST_BORROW_5 551 -#define _LOAD_FAST_BORROW_6 552 -#define _LOAD_FAST_BORROW_7 553 +#define _LOAD_FAST_BORROW 547 +#define _LOAD_FAST_BORROW_0 548 +#define _LOAD_FAST_BORROW_1 549 +#define _LOAD_FAST_BORROW_2 550 +#define _LOAD_FAST_BORROW_3 551 +#define _LOAD_FAST_BORROW_4 552 +#define _LOAD_FAST_BORROW_5 553 +#define _LOAD_FAST_BORROW_6 554 +#define _LOAD_FAST_BORROW_7 555 #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 554 -#define _LOAD_GLOBAL_BUILTINS 555 -#define _LOAD_GLOBAL_MODULE 556 +#define _LOAD_GLOBAL 556 +#define _LOAD_GLOBAL_BUILTINS 557 +#define _LOAD_GLOBAL_MODULE 558 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 557 -#define _LOAD_SMALL_INT_0 558 -#define _LOAD_SMALL_INT_1 559 -#define _LOAD_SMALL_INT_2 560 -#define _LOAD_SMALL_INT_3 561 -#define _LOAD_SPECIAL 562 +#define _LOAD_SMALL_INT 559 +#define _LOAD_SMALL_INT_0 560 +#define _LOAD_SMALL_INT_1 561 +#define _LOAD_SMALL_INT_2 562 +#define _LOAD_SMALL_INT_3 563 +#define _LOAD_SPECIAL 564 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR -#define _LOAD_SUPER_ATTR_METHOD 563 -#define _LOCK_OBJECT 564 -#define _MAKE_CALLARGS_A_TUPLE 565 +#define _LOAD_SUPER_ATTR_METHOD 565 +#define _LOCK_OBJECT 566 +#define _MAKE_CALLARGS_A_TUPLE 567 #define _MAKE_CELL MAKE_CELL -#define _MAKE_FUNCTION 566 -#define _MAKE_HEAP_SAFE 567 -#define _MAKE_WARM 568 +#define _MAKE_FUNCTION 568 +#define _MAKE_HEAP_SAFE 569 +#define _MAKE_WARM 570 #define _MAP_ADD MAP_ADD -#define _MATCH_CLASS 569 +#define _MATCH_CLASS 571 #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 570 -#define _MAYBE_EXPAND_METHOD_KW 571 -#define _MONITOR_CALL 572 -#define _MONITOR_CALL_KW 573 -#define _MONITOR_JUMP_BACKWARD 574 -#define _MONITOR_RESUME 575 +#define _MAYBE_EXPAND_METHOD 572 +#define _MAYBE_EXPAND_METHOD_KW 573 +#define _MONITOR_CALL 574 +#define _MONITOR_CALL_KW 575 +#define _MONITOR_JUMP_BACKWARD 576 +#define _MONITOR_RESUME 577 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT #define _POP_ITER POP_ITER -#define _POP_JUMP_IF_FALSE 576 -#define _POP_JUMP_IF_TRUE 577 +#define _POP_JUMP_IF_FALSE 578 +#define _POP_JUMP_IF_TRUE 579 #define _POP_TOP POP_TOP -#define _POP_TOP_FLOAT 578 -#define _POP_TOP_INT 579 -#define _POP_TOP_NOP 580 -#define _POP_TOP_OPARG 581 -#define _POP_TOP_UNICODE 582 +#define _POP_TOP_FLOAT 580 +#define _POP_TOP_INT 581 +#define _POP_TOP_NOP 582 +#define _POP_TOP_OPARG 583 +#define _POP_TOP_UNICODE 584 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 583 +#define _PUSH_FRAME 585 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 584 -#define _PUSH_TAGGED_ZERO 585 -#define _PY_FRAME_EX 586 -#define _PY_FRAME_GENERAL 587 -#define _PY_FRAME_KW 588 -#define _RECORD_3OS_GEN_FUNC 589 -#define _RECORD_4OS 590 -#define _RECORD_BOUND_METHOD 591 -#define _RECORD_CALLABLE 592 -#define _RECORD_CALLABLE_KW 593 -#define _RECORD_CODE 594 -#define _RECORD_NOS 595 -#define _RECORD_NOS_GEN_FUNC 596 -#define _RECORD_NOS_TYPE 597 -#define _RECORD_TOS 598 -#define _RECORD_TOS_TYPE 599 -#define _REPLACE_WITH_TRUE 600 -#define _RESUME_CHECK 601 +#define _PUSH_NULL_CONDITIONAL 586 +#define _PUSH_TAGGED_ZERO 587 +#define _PY_FRAME_EX 588 +#define _PY_FRAME_GENERAL 589 +#define _PY_FRAME_KW 590 +#define _RECORD_3OS_GEN_FUNC 591 +#define _RECORD_4OS 592 +#define _RECORD_BOUND_METHOD 593 +#define _RECORD_CALLABLE 594 +#define _RECORD_CALLABLE_KW 595 +#define _RECORD_CODE 596 +#define _RECORD_NOS 597 +#define _RECORD_NOS_GEN_FUNC 598 +#define _RECORD_NOS_TYPE 599 +#define _RECORD_TOS 600 +#define _RECORD_TOS_TYPE 601 +#define _REPLACE_WITH_TRUE 602 +#define _RESUME_CHECK 603 #define _RETURN_GENERATOR RETURN_GENERATOR -#define _RETURN_VALUE 602 -#define _RROT_3 603 -#define _SAVE_RETURN_OFFSET 604 -#define _SEND 605 -#define _SEND_GEN_FRAME 606 +#define _RETURN_VALUE 604 +#define _RROT_3 605 +#define _SAVE_RETURN_OFFSET 606 +#define _SEND 607 +#define _SEND_GEN_FRAME 608 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE -#define _SET_UPDATE 607 -#define _SPILL_OR_RELOAD 608 -#define _START_EXECUTOR 609 -#define _STORE_ATTR 610 -#define _STORE_ATTR_INSTANCE_VALUE 611 -#define _STORE_ATTR_SLOT 612 -#define _STORE_ATTR_WITH_HINT 613 +#define _SET_UPDATE 609 +#define _SPILL_OR_RELOAD 610 +#define _START_EXECUTOR 611 +#define _STORE_ATTR 612 +#define _STORE_ATTR_INSTANCE_VALUE 613 +#define _STORE_ATTR_SLOT 614 +#define _STORE_ATTR_WITH_HINT 615 #define _STORE_DEREF STORE_DEREF #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 614 -#define _STORE_SUBSCR 615 -#define _STORE_SUBSCR_DICT 616 -#define _STORE_SUBSCR_DICT_KNOWN_HASH 617 -#define _STORE_SUBSCR_LIST_INT 618 -#define _SWAP 619 -#define _SWAP_2 620 -#define _SWAP_3 621 -#define _SWAP_FAST 622 -#define _SWAP_FAST_0 623 -#define _SWAP_FAST_1 624 -#define _SWAP_FAST_2 625 -#define _SWAP_FAST_3 626 -#define _SWAP_FAST_4 627 -#define _SWAP_FAST_5 628 -#define _SWAP_FAST_6 629 -#define _SWAP_FAST_7 630 -#define _TIER2_RESUME_CHECK 631 -#define _TO_BOOL 632 +#define _STORE_SLICE 616 +#define _STORE_SUBSCR 617 +#define _STORE_SUBSCR_DICT 618 +#define _STORE_SUBSCR_DICT_KNOWN_HASH 619 +#define _STORE_SUBSCR_LIST_INT 620 +#define _SWAP 621 +#define _SWAP_2 622 +#define _SWAP_3 623 +#define _SWAP_FAST 624 +#define _SWAP_FAST_0 625 +#define _SWAP_FAST_1 626 +#define _SWAP_FAST_2 627 +#define _SWAP_FAST_3 628 +#define _SWAP_FAST_4 629 +#define _SWAP_FAST_5 630 +#define _SWAP_FAST_6 631 +#define _SWAP_FAST_7 632 +#define _TIER2_RESUME_CHECK 633 +#define _TO_BOOL 634 #define _TO_BOOL_BOOL TO_BOOL_BOOL -#define _TO_BOOL_INT 633 -#define _TO_BOOL_LIST 634 +#define _TO_BOOL_INT 635 +#define _TO_BOOL_LIST 636 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 635 +#define _TO_BOOL_STR 637 #define _TRACE_RECORD TRACE_RECORD -#define _UNARY_INVERT 636 -#define _UNARY_NEGATIVE 637 -#define _UNARY_NEGATIVE_FLOAT_INPLACE 638 +#define _UNARY_INVERT 638 +#define _UNARY_NEGATIVE 639 +#define _UNARY_NEGATIVE_FLOAT_INPLACE 640 #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 639 -#define _UNPACK_SEQUENCE_LIST 640 -#define _UNPACK_SEQUENCE_TUPLE 641 -#define _UNPACK_SEQUENCE_TWO_TUPLE 642 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE 643 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE 644 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE 645 +#define _UNPACK_SEQUENCE 641 +#define _UNPACK_SEQUENCE_LIST 642 +#define _UNPACK_SEQUENCE_TUPLE 643 +#define _UNPACK_SEQUENCE_TWO_TUPLE 644 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE 645 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE 646 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE 647 #define _WITH_EXCEPT_START WITH_EXCEPT_START -#define _YIELD_VALUE 646 -#define MAX_UOP_ID 646 -#define _ALLOCATE_OBJECT_r00 647 -#define _BINARY_OP_r23 648 -#define _BINARY_OP_ADD_FLOAT_r03 649 -#define _BINARY_OP_ADD_FLOAT_r13 650 -#define _BINARY_OP_ADD_FLOAT_r23 651 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r03 652 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r13 653 -#define _BINARY_OP_ADD_FLOAT_INPLACE_r23 654 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r03 655 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r13 656 -#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r23 657 -#define _BINARY_OP_ADD_INT_r03 658 -#define _BINARY_OP_ADD_INT_r13 659 -#define _BINARY_OP_ADD_INT_r23 660 -#define _BINARY_OP_ADD_INT_INPLACE_r03 661 -#define _BINARY_OP_ADD_INT_INPLACE_r13 662 -#define _BINARY_OP_ADD_INT_INPLACE_r23 663 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r03 664 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r13 665 -#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r23 666 -#define _BINARY_OP_ADD_UNICODE_r03 667 -#define _BINARY_OP_ADD_UNICODE_r13 668 -#define _BINARY_OP_ADD_UNICODE_r23 669 -#define _BINARY_OP_EXTEND_r23 670 -#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 671 -#define _BINARY_OP_MULTIPLY_FLOAT_r03 672 -#define _BINARY_OP_MULTIPLY_FLOAT_r13 673 -#define _BINARY_OP_MULTIPLY_FLOAT_r23 674 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r03 675 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r13 676 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r23 677 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r03 678 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r13 679 -#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r23 680 -#define _BINARY_OP_MULTIPLY_INT_r03 681 -#define _BINARY_OP_MULTIPLY_INT_r13 682 -#define _BINARY_OP_MULTIPLY_INT_r23 683 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r03 684 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r13 685 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_r23 686 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r03 687 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r13 688 -#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r23 689 -#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 690 -#define _BINARY_OP_SUBSCR_DICT_r23 691 -#define _BINARY_OP_SUBSCR_DICT_KNOWN_HASH_r23 692 -#define _BINARY_OP_SUBSCR_INIT_CALL_r01 693 -#define _BINARY_OP_SUBSCR_INIT_CALL_r11 694 -#define _BINARY_OP_SUBSCR_INIT_CALL_r21 695 -#define _BINARY_OP_SUBSCR_INIT_CALL_r31 696 -#define _BINARY_OP_SUBSCR_LIST_INT_r23 697 -#define _BINARY_OP_SUBSCR_LIST_SLICE_r23 698 -#define _BINARY_OP_SUBSCR_STR_INT_r23 699 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 700 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 701 -#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 702 -#define _BINARY_OP_SUBSCR_USTR_INT_r23 703 -#define _BINARY_OP_SUBTRACT_FLOAT_r03 704 -#define _BINARY_OP_SUBTRACT_FLOAT_r13 705 -#define _BINARY_OP_SUBTRACT_FLOAT_r23 706 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r03 707 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r13 708 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r23 709 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r03 710 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r13 711 -#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r23 712 -#define _BINARY_OP_SUBTRACT_INT_r03 713 -#define _BINARY_OP_SUBTRACT_INT_r13 714 -#define _BINARY_OP_SUBTRACT_INT_r23 715 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r03 716 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r13 717 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_r23 718 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r03 719 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r13 720 -#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r23 721 -#define _BINARY_OP_TRUEDIV_FLOAT_r23 722 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r03 723 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r13 724 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r23 725 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r03 726 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r13 727 -#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r23 728 -#define _BINARY_SLICE_r31 729 -#define _BUILD_INTERPOLATION_r01 730 -#define _BUILD_LIST_r01 731 -#define _BUILD_MAP_r01 732 -#define _BUILD_SET_r01 733 -#define _BUILD_SLICE_r01 734 -#define _BUILD_STRING_r01 735 -#define _BUILD_TEMPLATE_r21 736 -#define _BUILD_TUPLE_r01 737 -#define _CALL_BUILTIN_CLASS_r00 738 -#define _CALL_BUILTIN_FAST_r00 739 -#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r00 740 -#define _CALL_BUILTIN_O_r03 741 -#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 742 -#define _CALL_INTRINSIC_1_r12 743 -#define _CALL_INTRINSIC_2_r23 744 -#define _CALL_ISINSTANCE_r31 745 -#define _CALL_KW_NON_PY_r11 746 -#define _CALL_LEN_r33 747 -#define _CALL_LIST_APPEND_r03 748 -#define _CALL_LIST_APPEND_r13 749 -#define _CALL_LIST_APPEND_r23 750 -#define _CALL_LIST_APPEND_r33 751 -#define _CALL_METHOD_DESCRIPTOR_FAST_r00 752 -#define _CALL_METHOD_DESCRIPTOR_FAST_INLINE_r00 753 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 754 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE_r00 755 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_r03 756 -#define _CALL_METHOD_DESCRIPTOR_NOARGS_INLINE_r03 757 -#define _CALL_METHOD_DESCRIPTOR_O_r03 758 -#define _CALL_METHOD_DESCRIPTOR_O_INLINE_r03 759 -#define _CALL_NON_PY_GENERAL_r01 760 -#define _CALL_STR_1_r32 761 -#define _CALL_TUPLE_1_r32 762 -#define _CALL_TYPE_1_r02 763 -#define _CALL_TYPE_1_r12 764 -#define _CALL_TYPE_1_r22 765 -#define _CALL_TYPE_1_r32 766 -#define _CHECK_ATTR_CLASS_r01 767 -#define _CHECK_ATTR_CLASS_r11 768 -#define _CHECK_ATTR_CLASS_r22 769 -#define _CHECK_ATTR_CLASS_r33 770 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 771 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 772 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 773 -#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 774 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 775 -#define _CHECK_EG_MATCH_r22 776 -#define _CHECK_EXC_MATCH_r22 777 -#define _CHECK_FUNCTION_EXACT_ARGS_r00 778 -#define _CHECK_FUNCTION_VERSION_r00 779 -#define _CHECK_FUNCTION_VERSION_INLINE_r00 780 -#define _CHECK_FUNCTION_VERSION_INLINE_r11 781 -#define _CHECK_FUNCTION_VERSION_INLINE_r22 782 -#define _CHECK_FUNCTION_VERSION_INLINE_r33 783 -#define _CHECK_FUNCTION_VERSION_KW_r11 784 -#define _CHECK_IS_NOT_PY_CALLABLE_r00 785 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 786 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 787 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 788 -#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 789 -#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 790 -#define _CHECK_IS_PY_CALLABLE_EX_r03 791 -#define _CHECK_IS_PY_CALLABLE_EX_r13 792 -#define _CHECK_IS_PY_CALLABLE_EX_r23 793 -#define _CHECK_IS_PY_CALLABLE_EX_r33 794 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 795 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 796 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 797 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 798 -#define _CHECK_METHOD_VERSION_r00 799 -#define _CHECK_METHOD_VERSION_KW_r11 800 -#define _CHECK_OBJECT_r00 801 -#define _CHECK_PEP_523_r00 802 -#define _CHECK_PEP_523_r11 803 -#define _CHECK_PEP_523_r22 804 -#define _CHECK_PEP_523_r33 805 -#define _CHECK_PERIODIC_r00 806 -#define _CHECK_PERIODIC_AT_END_r00 807 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 808 -#define _CHECK_RECURSION_LIMIT_r00 809 -#define _CHECK_RECURSION_LIMIT_r11 810 -#define _CHECK_RECURSION_LIMIT_r22 811 -#define _CHECK_RECURSION_LIMIT_r33 812 -#define _CHECK_RECURSION_REMAINING_r00 813 -#define _CHECK_RECURSION_REMAINING_r11 814 -#define _CHECK_RECURSION_REMAINING_r22 815 -#define _CHECK_RECURSION_REMAINING_r33 816 -#define _CHECK_STACK_SPACE_r00 817 -#define _CHECK_STACK_SPACE_OPERAND_r00 818 -#define _CHECK_STACK_SPACE_OPERAND_r11 819 -#define _CHECK_STACK_SPACE_OPERAND_r22 820 -#define _CHECK_STACK_SPACE_OPERAND_r33 821 -#define _CHECK_VALIDITY_r00 822 -#define _CHECK_VALIDITY_r11 823 -#define _CHECK_VALIDITY_r22 824 -#define _CHECK_VALIDITY_r33 825 -#define _COLD_DYNAMIC_EXIT_r00 826 -#define _COLD_EXIT_r00 827 -#define _COMPARE_OP_r21 828 -#define _COMPARE_OP_FLOAT_r03 829 -#define _COMPARE_OP_FLOAT_r13 830 -#define _COMPARE_OP_FLOAT_r23 831 -#define _COMPARE_OP_INT_r23 832 -#define _COMPARE_OP_STR_r23 833 -#define _CONTAINS_OP_r23 834 -#define _CONTAINS_OP_DICT_r23 835 -#define _CONTAINS_OP_SET_r23 836 -#define _CONVERT_VALUE_r11 837 -#define _COPY_r01 838 -#define _COPY_1_r02 839 -#define _COPY_1_r12 840 -#define _COPY_1_r23 841 -#define _COPY_2_r03 842 -#define _COPY_2_r13 843 -#define _COPY_2_r23 844 -#define _COPY_3_r03 845 -#define _COPY_3_r13 846 -#define _COPY_3_r23 847 -#define _COPY_3_r33 848 -#define _COPY_FREE_VARS_r00 849 -#define _COPY_FREE_VARS_r11 850 -#define _COPY_FREE_VARS_r22 851 -#define _COPY_FREE_VARS_r33 852 -#define _CREATE_INIT_FRAME_r01 853 -#define _DELETE_ATTR_r10 854 -#define _DELETE_DEREF_r00 855 -#define _DELETE_FAST_r00 856 -#define _DELETE_GLOBAL_r00 857 -#define _DELETE_NAME_r00 858 -#define _DELETE_SUBSCR_r20 859 -#define _DEOPT_r00 860 -#define _DEOPT_r10 861 -#define _DEOPT_r20 862 -#define _DEOPT_r30 863 -#define _DICT_MERGE_r11 864 -#define _DICT_UPDATE_r11 865 -#define _DO_CALL_r01 866 -#define _DO_CALL_FUNCTION_EX_r31 867 -#define _DO_CALL_KW_r11 868 -#define _DYNAMIC_EXIT_r00 869 -#define _DYNAMIC_EXIT_r10 870 -#define _DYNAMIC_EXIT_r20 871 -#define _DYNAMIC_EXIT_r30 872 -#define _END_FOR_r10 873 -#define _END_SEND_r31 874 -#define _ERROR_POP_N_r00 875 -#define _EXIT_INIT_CHECK_r10 876 -#define _EXIT_TRACE_r00 877 -#define _EXIT_TRACE_r10 878 -#define _EXIT_TRACE_r20 879 -#define _EXIT_TRACE_r30 880 -#define _EXPAND_METHOD_r00 881 -#define _EXPAND_METHOD_KW_r11 882 -#define _FATAL_ERROR_r00 883 -#define _FATAL_ERROR_r11 884 -#define _FATAL_ERROR_r22 885 -#define _FATAL_ERROR_r33 886 -#define _FORMAT_SIMPLE_r11 887 -#define _FORMAT_WITH_SPEC_r21 888 -#define _FOR_ITER_r23 889 -#define _FOR_ITER_GEN_FRAME_r03 890 -#define _FOR_ITER_GEN_FRAME_r13 891 -#define _FOR_ITER_GEN_FRAME_r23 892 -#define _FOR_ITER_TIER_TWO_r23 893 -#define _FOR_ITER_VIRTUAL_r23 894 -#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 895 -#define _GET_AITER_r11 896 -#define _GET_ANEXT_r12 897 -#define _GET_AWAITABLE_r11 898 -#define _GET_ITER_r12 899 -#define _GET_ITER_TRAD_r12 900 -#define _GET_LEN_r12 901 -#define _GUARD_BINARY_OP_EXTEND_r22 902 -#define _GUARD_BINARY_OP_EXTEND_LHS_r02 903 -#define _GUARD_BINARY_OP_EXTEND_LHS_r12 904 -#define _GUARD_BINARY_OP_EXTEND_LHS_r22 905 -#define _GUARD_BINARY_OP_EXTEND_LHS_r33 906 -#define _GUARD_BINARY_OP_EXTEND_RHS_r02 907 -#define _GUARD_BINARY_OP_EXTEND_RHS_r12 908 -#define _GUARD_BINARY_OP_EXTEND_RHS_r22 909 -#define _GUARD_BINARY_OP_EXTEND_RHS_r33 910 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 911 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 912 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 913 -#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 914 -#define _GUARD_BIT_IS_SET_POP_r00 915 -#define _GUARD_BIT_IS_SET_POP_r10 916 -#define _GUARD_BIT_IS_SET_POP_r21 917 -#define _GUARD_BIT_IS_SET_POP_r32 918 -#define _GUARD_BIT_IS_SET_POP_4_r00 919 -#define _GUARD_BIT_IS_SET_POP_4_r10 920 -#define _GUARD_BIT_IS_SET_POP_4_r21 921 -#define _GUARD_BIT_IS_SET_POP_4_r32 922 -#define _GUARD_BIT_IS_SET_POP_5_r00 923 -#define _GUARD_BIT_IS_SET_POP_5_r10 924 -#define _GUARD_BIT_IS_SET_POP_5_r21 925 -#define _GUARD_BIT_IS_SET_POP_5_r32 926 -#define _GUARD_BIT_IS_SET_POP_6_r00 927 -#define _GUARD_BIT_IS_SET_POP_6_r10 928 -#define _GUARD_BIT_IS_SET_POP_6_r21 929 -#define _GUARD_BIT_IS_SET_POP_6_r32 930 -#define _GUARD_BIT_IS_SET_POP_7_r00 931 -#define _GUARD_BIT_IS_SET_POP_7_r10 932 -#define _GUARD_BIT_IS_SET_POP_7_r21 933 -#define _GUARD_BIT_IS_SET_POP_7_r32 934 -#define _GUARD_BIT_IS_UNSET_POP_r00 935 -#define _GUARD_BIT_IS_UNSET_POP_r10 936 -#define _GUARD_BIT_IS_UNSET_POP_r21 937 -#define _GUARD_BIT_IS_UNSET_POP_r32 938 -#define _GUARD_BIT_IS_UNSET_POP_4_r00 939 -#define _GUARD_BIT_IS_UNSET_POP_4_r10 940 -#define _GUARD_BIT_IS_UNSET_POP_4_r21 941 -#define _GUARD_BIT_IS_UNSET_POP_4_r32 942 -#define _GUARD_BIT_IS_UNSET_POP_5_r00 943 -#define _GUARD_BIT_IS_UNSET_POP_5_r10 944 -#define _GUARD_BIT_IS_UNSET_POP_5_r21 945 -#define _GUARD_BIT_IS_UNSET_POP_5_r32 946 -#define _GUARD_BIT_IS_UNSET_POP_6_r00 947 -#define _GUARD_BIT_IS_UNSET_POP_6_r10 948 -#define _GUARD_BIT_IS_UNSET_POP_6_r21 949 -#define _GUARD_BIT_IS_UNSET_POP_6_r32 950 -#define _GUARD_BIT_IS_UNSET_POP_7_r00 951 -#define _GUARD_BIT_IS_UNSET_POP_7_r10 952 -#define _GUARD_BIT_IS_UNSET_POP_7_r21 953 -#define _GUARD_BIT_IS_UNSET_POP_7_r32 954 -#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 955 -#define _GUARD_CALLABLE_BUILTIN_FAST_r00 956 -#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 957 -#define _GUARD_CALLABLE_BUILTIN_O_r00 958 -#define _GUARD_CALLABLE_ISINSTANCE_r03 959 -#define _GUARD_CALLABLE_ISINSTANCE_r13 960 -#define _GUARD_CALLABLE_ISINSTANCE_r23 961 -#define _GUARD_CALLABLE_ISINSTANCE_r33 962 -#define _GUARD_CALLABLE_LEN_r03 963 -#define _GUARD_CALLABLE_LEN_r13 964 -#define _GUARD_CALLABLE_LEN_r23 965 -#define _GUARD_CALLABLE_LEN_r33 966 -#define _GUARD_CALLABLE_LIST_APPEND_r03 967 -#define _GUARD_CALLABLE_LIST_APPEND_r13 968 -#define _GUARD_CALLABLE_LIST_APPEND_r23 969 -#define _GUARD_CALLABLE_LIST_APPEND_r33 970 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 971 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 972 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 973 -#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 974 -#define _GUARD_CALLABLE_STR_1_r03 975 -#define _GUARD_CALLABLE_STR_1_r13 976 -#define _GUARD_CALLABLE_STR_1_r23 977 -#define _GUARD_CALLABLE_STR_1_r33 978 -#define _GUARD_CALLABLE_TUPLE_1_r03 979 -#define _GUARD_CALLABLE_TUPLE_1_r13 980 -#define _GUARD_CALLABLE_TUPLE_1_r23 981 -#define _GUARD_CALLABLE_TUPLE_1_r33 982 -#define _GUARD_CALLABLE_TYPE_1_r03 983 -#define _GUARD_CALLABLE_TYPE_1_r13 984 -#define _GUARD_CALLABLE_TYPE_1_r23 985 -#define _GUARD_CALLABLE_TYPE_1_r33 986 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 987 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 988 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 989 -#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 990 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 991 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 992 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 993 -#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 994 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 995 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 996 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 997 -#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 998 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 999 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1000 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1001 -#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1002 -#define _GUARD_DORV_NO_DICT_r01 1003 -#define _GUARD_DORV_NO_DICT_r11 1004 -#define _GUARD_DORV_NO_DICT_r22 1005 -#define _GUARD_DORV_NO_DICT_r33 1006 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 1007 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 1008 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 1009 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 1010 -#define _GUARD_GLOBALS_VERSION_r00 1011 -#define _GUARD_GLOBALS_VERSION_r11 1012 -#define _GUARD_GLOBALS_VERSION_r22 1013 -#define _GUARD_GLOBALS_VERSION_r33 1014 -#define _GUARD_IP_RETURN_GENERATOR_r00 1015 -#define _GUARD_IP_RETURN_GENERATOR_r11 1016 -#define _GUARD_IP_RETURN_GENERATOR_r22 1017 -#define _GUARD_IP_RETURN_GENERATOR_r33 1018 -#define _GUARD_IP_RETURN_VALUE_r00 1019 -#define _GUARD_IP_RETURN_VALUE_r11 1020 -#define _GUARD_IP_RETURN_VALUE_r22 1021 -#define _GUARD_IP_RETURN_VALUE_r33 1022 -#define _GUARD_IP_YIELD_VALUE_r00 1023 -#define _GUARD_IP_YIELD_VALUE_r11 1024 -#define _GUARD_IP_YIELD_VALUE_r22 1025 -#define _GUARD_IP_YIELD_VALUE_r33 1026 -#define _GUARD_IP__PUSH_FRAME_r00 1027 -#define _GUARD_IP__PUSH_FRAME_r11 1028 -#define _GUARD_IP__PUSH_FRAME_r22 1029 -#define _GUARD_IP__PUSH_FRAME_r33 1030 -#define _GUARD_IS_FALSE_POP_r00 1031 -#define _GUARD_IS_FALSE_POP_r10 1032 -#define _GUARD_IS_FALSE_POP_r21 1033 -#define _GUARD_IS_FALSE_POP_r32 1034 -#define _GUARD_IS_NONE_POP_r00 1035 -#define _GUARD_IS_NONE_POP_r10 1036 -#define _GUARD_IS_NONE_POP_r21 1037 -#define _GUARD_IS_NONE_POP_r32 1038 -#define _GUARD_IS_NOT_NONE_POP_r10 1039 -#define _GUARD_IS_TRUE_POP_r00 1040 -#define _GUARD_IS_TRUE_POP_r10 1041 -#define _GUARD_IS_TRUE_POP_r21 1042 -#define _GUARD_IS_TRUE_POP_r32 1043 -#define _GUARD_ITERATOR_r01 1044 -#define _GUARD_ITERATOR_r11 1045 -#define _GUARD_ITERATOR_r22 1046 -#define _GUARD_ITERATOR_r33 1047 -#define _GUARD_ITER_VIRTUAL_r01 1048 -#define _GUARD_ITER_VIRTUAL_r11 1049 -#define _GUARD_ITER_VIRTUAL_r22 1050 -#define _GUARD_ITER_VIRTUAL_r33 1051 -#define _GUARD_KEYS_VERSION_r01 1052 -#define _GUARD_KEYS_VERSION_r11 1053 -#define _GUARD_KEYS_VERSION_r22 1054 -#define _GUARD_KEYS_VERSION_r33 1055 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1056 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1057 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1058 -#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1059 -#define _GUARD_NOS_COMPACT_ASCII_r02 1060 -#define _GUARD_NOS_COMPACT_ASCII_r12 1061 -#define _GUARD_NOS_COMPACT_ASCII_r22 1062 -#define _GUARD_NOS_COMPACT_ASCII_r33 1063 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1064 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1065 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1066 -#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1067 -#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1068 -#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1069 -#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1070 -#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1071 -#define _GUARD_NOS_FLOAT_r02 1072 -#define _GUARD_NOS_FLOAT_r12 1073 -#define _GUARD_NOS_FLOAT_r22 1074 -#define _GUARD_NOS_FLOAT_r33 1075 -#define _GUARD_NOS_INT_r02 1076 -#define _GUARD_NOS_INT_r12 1077 -#define _GUARD_NOS_INT_r22 1078 -#define _GUARD_NOS_INT_r33 1079 -#define _GUARD_NOS_ITER_VIRTUAL_r02 1080 -#define _GUARD_NOS_ITER_VIRTUAL_r12 1081 -#define _GUARD_NOS_ITER_VIRTUAL_r22 1082 -#define _GUARD_NOS_ITER_VIRTUAL_r33 1083 -#define _GUARD_NOS_LIST_r02 1084 -#define _GUARD_NOS_LIST_r12 1085 -#define _GUARD_NOS_LIST_r22 1086 -#define _GUARD_NOS_LIST_r33 1087 -#define _GUARD_NOS_NOT_NULL_r02 1088 -#define _GUARD_NOS_NOT_NULL_r12 1089 -#define _GUARD_NOS_NOT_NULL_r22 1090 -#define _GUARD_NOS_NOT_NULL_r33 1091 -#define _GUARD_NOS_NULL_r02 1092 -#define _GUARD_NOS_NULL_r12 1093 -#define _GUARD_NOS_NULL_r22 1094 -#define _GUARD_NOS_NULL_r33 1095 -#define _GUARD_NOS_OVERFLOWED_r02 1096 -#define _GUARD_NOS_OVERFLOWED_r12 1097 -#define _GUARD_NOS_OVERFLOWED_r22 1098 -#define _GUARD_NOS_OVERFLOWED_r33 1099 -#define _GUARD_NOS_TUPLE_r02 1100 -#define _GUARD_NOS_TUPLE_r12 1101 -#define _GUARD_NOS_TUPLE_r22 1102 -#define _GUARD_NOS_TUPLE_r33 1103 -#define _GUARD_NOS_TYPE_VERSION_r02 1104 -#define _GUARD_NOS_TYPE_VERSION_r12 1105 -#define _GUARD_NOS_TYPE_VERSION_r22 1106 -#define _GUARD_NOS_TYPE_VERSION_r33 1107 -#define _GUARD_NOS_UNICODE_r02 1108 -#define _GUARD_NOS_UNICODE_r12 1109 -#define _GUARD_NOS_UNICODE_r22 1110 -#define _GUARD_NOS_UNICODE_r33 1111 -#define _GUARD_NOT_EXHAUSTED_LIST_r02 1112 -#define _GUARD_NOT_EXHAUSTED_LIST_r12 1113 -#define _GUARD_NOT_EXHAUSTED_LIST_r22 1114 -#define _GUARD_NOT_EXHAUSTED_LIST_r33 1115 -#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1116 -#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1117 -#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1118 -#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1119 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1120 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1121 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1122 -#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1123 -#define _GUARD_THIRD_NULL_r03 1124 -#define _GUARD_THIRD_NULL_r13 1125 -#define _GUARD_THIRD_NULL_r23 1126 -#define _GUARD_THIRD_NULL_r33 1127 -#define _GUARD_TOS_ANY_DICT_r01 1128 -#define _GUARD_TOS_ANY_DICT_r11 1129 -#define _GUARD_TOS_ANY_DICT_r22 1130 -#define _GUARD_TOS_ANY_DICT_r33 1131 -#define _GUARD_TOS_ANY_SET_r01 1132 -#define _GUARD_TOS_ANY_SET_r11 1133 -#define _GUARD_TOS_ANY_SET_r22 1134 -#define _GUARD_TOS_ANY_SET_r33 1135 -#define _GUARD_TOS_DICT_r01 1136 -#define _GUARD_TOS_DICT_r11 1137 -#define _GUARD_TOS_DICT_r22 1138 -#define _GUARD_TOS_DICT_r33 1139 -#define _GUARD_TOS_FLOAT_r01 1140 -#define _GUARD_TOS_FLOAT_r11 1141 -#define _GUARD_TOS_FLOAT_r22 1142 -#define _GUARD_TOS_FLOAT_r33 1143 -#define _GUARD_TOS_FROZENDICT_r01 1144 -#define _GUARD_TOS_FROZENDICT_r11 1145 -#define _GUARD_TOS_FROZENDICT_r22 1146 -#define _GUARD_TOS_FROZENDICT_r33 1147 -#define _GUARD_TOS_FROZENSET_r01 1148 -#define _GUARD_TOS_FROZENSET_r11 1149 -#define _GUARD_TOS_FROZENSET_r22 1150 -#define _GUARD_TOS_FROZENSET_r33 1151 -#define _GUARD_TOS_INT_r01 1152 -#define _GUARD_TOS_INT_r11 1153 -#define _GUARD_TOS_INT_r22 1154 -#define _GUARD_TOS_INT_r33 1155 -#define _GUARD_TOS_LIST_r01 1156 -#define _GUARD_TOS_LIST_r11 1157 -#define _GUARD_TOS_LIST_r22 1158 -#define _GUARD_TOS_LIST_r33 1159 -#define _GUARD_TOS_OVERFLOWED_r01 1160 -#define _GUARD_TOS_OVERFLOWED_r11 1161 -#define _GUARD_TOS_OVERFLOWED_r22 1162 -#define _GUARD_TOS_OVERFLOWED_r33 1163 -#define _GUARD_TOS_SET_r01 1164 -#define _GUARD_TOS_SET_r11 1165 -#define _GUARD_TOS_SET_r22 1166 -#define _GUARD_TOS_SET_r33 1167 -#define _GUARD_TOS_SLICE_r01 1168 -#define _GUARD_TOS_SLICE_r11 1169 -#define _GUARD_TOS_SLICE_r22 1170 -#define _GUARD_TOS_SLICE_r33 1171 -#define _GUARD_TOS_TUPLE_r01 1172 -#define _GUARD_TOS_TUPLE_r11 1173 -#define _GUARD_TOS_TUPLE_r22 1174 -#define _GUARD_TOS_TUPLE_r33 1175 -#define _GUARD_TOS_UNICODE_r01 1176 -#define _GUARD_TOS_UNICODE_r11 1177 -#define _GUARD_TOS_UNICODE_r22 1178 -#define _GUARD_TOS_UNICODE_r33 1179 -#define _GUARD_TYPE_r01 1180 -#define _GUARD_TYPE_r11 1181 -#define _GUARD_TYPE_r22 1182 -#define _GUARD_TYPE_r33 1183 -#define _GUARD_TYPE_VERSION_r01 1184 -#define _GUARD_TYPE_VERSION_r11 1185 -#define _GUARD_TYPE_VERSION_r22 1186 -#define _GUARD_TYPE_VERSION_r33 1187 -#define _GUARD_TYPE_VERSION_LOCKED_r01 1188 -#define _GUARD_TYPE_VERSION_LOCKED_r11 1189 -#define _GUARD_TYPE_VERSION_LOCKED_r22 1190 -#define _GUARD_TYPE_VERSION_LOCKED_r33 1191 -#define _HANDLE_PENDING_AND_DEOPT_r00 1192 -#define _HANDLE_PENDING_AND_DEOPT_r10 1193 -#define _HANDLE_PENDING_AND_DEOPT_r20 1194 -#define _HANDLE_PENDING_AND_DEOPT_r30 1195 -#define _IMPORT_FROM_r12 1196 -#define _IMPORT_NAME_r21 1197 -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1198 -#define _INIT_CALL_PY_EXACT_ARGS_r01 1199 -#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1200 -#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1201 -#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1202 -#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1203 -#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1204 -#define _INSERT_NULL_r10 1205 -#define _INSTRUMENTED_FOR_ITER_r23 1206 -#define _INSTRUMENTED_INSTRUCTION_r00 1207 -#define _INSTRUMENTED_JUMP_FORWARD_r00 1208 -#define _INSTRUMENTED_JUMP_FORWARD_r11 1209 -#define _INSTRUMENTED_JUMP_FORWARD_r22 1210 -#define _INSTRUMENTED_JUMP_FORWARD_r33 1211 -#define _INSTRUMENTED_LINE_r00 1212 -#define _INSTRUMENTED_NOT_TAKEN_r00 1213 -#define _INSTRUMENTED_NOT_TAKEN_r11 1214 -#define _INSTRUMENTED_NOT_TAKEN_r22 1215 -#define _INSTRUMENTED_NOT_TAKEN_r33 1216 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1217 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1218 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1219 -#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1220 -#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1221 -#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1222 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1223 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1224 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1225 -#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1226 -#define _IS_NONE_r11 1227 -#define _IS_OP_r03 1228 -#define _IS_OP_r13 1229 -#define _IS_OP_r23 1230 -#define _ITER_CHECK_LIST_r02 1231 -#define _ITER_CHECK_LIST_r12 1232 -#define _ITER_CHECK_LIST_r22 1233 -#define _ITER_CHECK_LIST_r33 1234 -#define _ITER_CHECK_RANGE_r02 1235 -#define _ITER_CHECK_RANGE_r12 1236 -#define _ITER_CHECK_RANGE_r22 1237 -#define _ITER_CHECK_RANGE_r33 1238 -#define _ITER_CHECK_TUPLE_r02 1239 -#define _ITER_CHECK_TUPLE_r12 1240 -#define _ITER_CHECK_TUPLE_r22 1241 -#define _ITER_CHECK_TUPLE_r33 1242 -#define _ITER_JUMP_LIST_r02 1243 -#define _ITER_JUMP_LIST_r12 1244 -#define _ITER_JUMP_LIST_r22 1245 -#define _ITER_JUMP_LIST_r33 1246 -#define _ITER_JUMP_RANGE_r02 1247 -#define _ITER_JUMP_RANGE_r12 1248 -#define _ITER_JUMP_RANGE_r22 1249 -#define _ITER_JUMP_RANGE_r33 1250 -#define _ITER_JUMP_TUPLE_r02 1251 -#define _ITER_JUMP_TUPLE_r12 1252 -#define _ITER_JUMP_TUPLE_r22 1253 -#define _ITER_JUMP_TUPLE_r33 1254 -#define _ITER_NEXT_LIST_r23 1255 -#define _ITER_NEXT_LIST_TIER_TWO_r23 1256 -#define _ITER_NEXT_RANGE_r03 1257 -#define _ITER_NEXT_RANGE_r13 1258 -#define _ITER_NEXT_RANGE_r23 1259 -#define _ITER_NEXT_TUPLE_r03 1260 -#define _ITER_NEXT_TUPLE_r13 1261 -#define _ITER_NEXT_TUPLE_r23 1262 -#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1263 -#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1264 -#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1265 -#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1266 -#define _JUMP_TO_TOP_r00 1267 -#define _LIST_APPEND_r10 1268 -#define _LIST_EXTEND_r11 1269 -#define _LOAD_ATTR_r10 1270 -#define _LOAD_ATTR_CLASS_r11 1271 -#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1272 -#define _LOAD_ATTR_INSTANCE_VALUE_r02 1273 -#define _LOAD_ATTR_INSTANCE_VALUE_r12 1274 -#define _LOAD_ATTR_INSTANCE_VALUE_r23 1275 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1276 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1277 -#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1278 -#define _LOAD_ATTR_METHOD_NO_DICT_r02 1279 -#define _LOAD_ATTR_METHOD_NO_DICT_r12 1280 -#define _LOAD_ATTR_METHOD_NO_DICT_r23 1281 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1282 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1283 -#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1284 -#define _LOAD_ATTR_MODULE_r12 1285 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1286 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1287 -#define _LOAD_ATTR_PROPERTY_FRAME_r01 1288 -#define _LOAD_ATTR_PROPERTY_FRAME_r11 1289 -#define _LOAD_ATTR_PROPERTY_FRAME_r22 1290 -#define _LOAD_ATTR_PROPERTY_FRAME_r33 1291 -#define _LOAD_ATTR_SLOT_r02 1292 -#define _LOAD_ATTR_SLOT_r12 1293 -#define _LOAD_ATTR_SLOT_r23 1294 -#define _LOAD_ATTR_WITH_HINT_r12 1295 -#define _LOAD_BUILD_CLASS_r01 1296 -#define _LOAD_BYTECODE_r00 1297 -#define _LOAD_COMMON_CONSTANT_r01 1298 -#define _LOAD_COMMON_CONSTANT_r12 1299 -#define _LOAD_COMMON_CONSTANT_r23 1300 -#define _LOAD_CONST_r01 1301 -#define _LOAD_CONST_r12 1302 -#define _LOAD_CONST_r23 1303 -#define _LOAD_CONST_INLINE_r01 1304 -#define _LOAD_CONST_INLINE_r12 1305 -#define _LOAD_CONST_INLINE_r23 1306 -#define _LOAD_CONST_INLINE_BORROW_r01 1307 -#define _LOAD_CONST_INLINE_BORROW_r12 1308 -#define _LOAD_CONST_INLINE_BORROW_r23 1309 -#define _LOAD_DEREF_r01 1310 -#define _LOAD_FAST_r01 1311 -#define _LOAD_FAST_r12 1312 -#define _LOAD_FAST_r23 1313 -#define _LOAD_FAST_0_r01 1314 -#define _LOAD_FAST_0_r12 1315 -#define _LOAD_FAST_0_r23 1316 -#define _LOAD_FAST_1_r01 1317 -#define _LOAD_FAST_1_r12 1318 -#define _LOAD_FAST_1_r23 1319 -#define _LOAD_FAST_2_r01 1320 -#define _LOAD_FAST_2_r12 1321 -#define _LOAD_FAST_2_r23 1322 -#define _LOAD_FAST_3_r01 1323 -#define _LOAD_FAST_3_r12 1324 -#define _LOAD_FAST_3_r23 1325 -#define _LOAD_FAST_4_r01 1326 -#define _LOAD_FAST_4_r12 1327 -#define _LOAD_FAST_4_r23 1328 -#define _LOAD_FAST_5_r01 1329 -#define _LOAD_FAST_5_r12 1330 -#define _LOAD_FAST_5_r23 1331 -#define _LOAD_FAST_6_r01 1332 -#define _LOAD_FAST_6_r12 1333 -#define _LOAD_FAST_6_r23 1334 -#define _LOAD_FAST_7_r01 1335 -#define _LOAD_FAST_7_r12 1336 -#define _LOAD_FAST_7_r23 1337 -#define _LOAD_FAST_AND_CLEAR_r01 1338 -#define _LOAD_FAST_AND_CLEAR_r12 1339 -#define _LOAD_FAST_AND_CLEAR_r23 1340 -#define _LOAD_FAST_BORROW_r01 1341 -#define _LOAD_FAST_BORROW_r12 1342 -#define _LOAD_FAST_BORROW_r23 1343 -#define _LOAD_FAST_BORROW_0_r01 1344 -#define _LOAD_FAST_BORROW_0_r12 1345 -#define _LOAD_FAST_BORROW_0_r23 1346 -#define _LOAD_FAST_BORROW_1_r01 1347 -#define _LOAD_FAST_BORROW_1_r12 1348 -#define _LOAD_FAST_BORROW_1_r23 1349 -#define _LOAD_FAST_BORROW_2_r01 1350 -#define _LOAD_FAST_BORROW_2_r12 1351 -#define _LOAD_FAST_BORROW_2_r23 1352 -#define _LOAD_FAST_BORROW_3_r01 1353 -#define _LOAD_FAST_BORROW_3_r12 1354 -#define _LOAD_FAST_BORROW_3_r23 1355 -#define _LOAD_FAST_BORROW_4_r01 1356 -#define _LOAD_FAST_BORROW_4_r12 1357 -#define _LOAD_FAST_BORROW_4_r23 1358 -#define _LOAD_FAST_BORROW_5_r01 1359 -#define _LOAD_FAST_BORROW_5_r12 1360 -#define _LOAD_FAST_BORROW_5_r23 1361 -#define _LOAD_FAST_BORROW_6_r01 1362 -#define _LOAD_FAST_BORROW_6_r12 1363 -#define _LOAD_FAST_BORROW_6_r23 1364 -#define _LOAD_FAST_BORROW_7_r01 1365 -#define _LOAD_FAST_BORROW_7_r12 1366 -#define _LOAD_FAST_BORROW_7_r23 1367 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1368 -#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1369 -#define _LOAD_FAST_CHECK_r01 1370 -#define _LOAD_FAST_CHECK_r12 1371 -#define _LOAD_FAST_CHECK_r23 1372 -#define _LOAD_FAST_LOAD_FAST_r02 1373 -#define _LOAD_FAST_LOAD_FAST_r13 1374 -#define _LOAD_FROM_DICT_OR_DEREF_r11 1375 -#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1376 -#define _LOAD_GLOBAL_r00 1377 -#define _LOAD_GLOBAL_BUILTINS_r01 1378 -#define _LOAD_GLOBAL_MODULE_r01 1379 -#define _LOAD_LOCALS_r01 1380 -#define _LOAD_LOCALS_r12 1381 -#define _LOAD_LOCALS_r23 1382 -#define _LOAD_NAME_r01 1383 -#define _LOAD_SMALL_INT_r01 1384 -#define _LOAD_SMALL_INT_r12 1385 -#define _LOAD_SMALL_INT_r23 1386 -#define _LOAD_SMALL_INT_0_r01 1387 -#define _LOAD_SMALL_INT_0_r12 1388 -#define _LOAD_SMALL_INT_0_r23 1389 -#define _LOAD_SMALL_INT_1_r01 1390 -#define _LOAD_SMALL_INT_1_r12 1391 -#define _LOAD_SMALL_INT_1_r23 1392 -#define _LOAD_SMALL_INT_2_r01 1393 -#define _LOAD_SMALL_INT_2_r12 1394 -#define _LOAD_SMALL_INT_2_r23 1395 -#define _LOAD_SMALL_INT_3_r01 1396 -#define _LOAD_SMALL_INT_3_r12 1397 -#define _LOAD_SMALL_INT_3_r23 1398 -#define _LOAD_SPECIAL_r00 1399 -#define _LOAD_SUPER_ATTR_ATTR_r31 1400 -#define _LOAD_SUPER_ATTR_METHOD_r32 1401 -#define _LOCK_OBJECT_r01 1402 -#define _LOCK_OBJECT_r11 1403 -#define _LOCK_OBJECT_r22 1404 -#define _LOCK_OBJECT_r33 1405 -#define _MAKE_CALLARGS_A_TUPLE_r33 1406 -#define _MAKE_CELL_r00 1407 -#define _MAKE_FUNCTION_r12 1408 -#define _MAKE_HEAP_SAFE_r01 1409 -#define _MAKE_HEAP_SAFE_r11 1410 -#define _MAKE_HEAP_SAFE_r22 1411 -#define _MAKE_HEAP_SAFE_r33 1412 -#define _MAKE_WARM_r00 1413 -#define _MAKE_WARM_r11 1414 -#define _MAKE_WARM_r22 1415 -#define _MAKE_WARM_r33 1416 -#define _MAP_ADD_r20 1417 -#define _MATCH_CLASS_r33 1418 -#define _MATCH_KEYS_r23 1419 -#define _MATCH_MAPPING_r02 1420 -#define _MATCH_MAPPING_r12 1421 -#define _MATCH_MAPPING_r23 1422 -#define _MATCH_SEQUENCE_r02 1423 -#define _MATCH_SEQUENCE_r12 1424 -#define _MATCH_SEQUENCE_r23 1425 -#define _MAYBE_EXPAND_METHOD_r00 1426 -#define _MAYBE_EXPAND_METHOD_KW_r11 1427 -#define _MONITOR_CALL_r00 1428 -#define _MONITOR_CALL_KW_r11 1429 -#define _MONITOR_JUMP_BACKWARD_r00 1430 -#define _MONITOR_JUMP_BACKWARD_r11 1431 -#define _MONITOR_JUMP_BACKWARD_r22 1432 -#define _MONITOR_JUMP_BACKWARD_r33 1433 -#define _MONITOR_RESUME_r00 1434 -#define _NOP_r00 1435 -#define _NOP_r11 1436 -#define _NOP_r22 1437 -#define _NOP_r33 1438 -#define _POP_EXCEPT_r10 1439 -#define _POP_ITER_r20 1440 -#define _POP_JUMP_IF_FALSE_r00 1441 -#define _POP_JUMP_IF_FALSE_r10 1442 -#define _POP_JUMP_IF_FALSE_r21 1443 -#define _POP_JUMP_IF_FALSE_r32 1444 -#define _POP_JUMP_IF_TRUE_r00 1445 -#define _POP_JUMP_IF_TRUE_r10 1446 -#define _POP_JUMP_IF_TRUE_r21 1447 -#define _POP_JUMP_IF_TRUE_r32 1448 -#define _POP_TOP_r10 1449 -#define _POP_TOP_FLOAT_r00 1450 -#define _POP_TOP_FLOAT_r10 1451 -#define _POP_TOP_FLOAT_r21 1452 -#define _POP_TOP_FLOAT_r32 1453 -#define _POP_TOP_INT_r00 1454 -#define _POP_TOP_INT_r10 1455 -#define _POP_TOP_INT_r21 1456 -#define _POP_TOP_INT_r32 1457 -#define _POP_TOP_NOP_r00 1458 -#define _POP_TOP_NOP_r10 1459 -#define _POP_TOP_NOP_r21 1460 -#define _POP_TOP_NOP_r32 1461 -#define _POP_TOP_OPARG_r00 1462 -#define _POP_TOP_UNICODE_r00 1463 -#define _POP_TOP_UNICODE_r10 1464 -#define _POP_TOP_UNICODE_r21 1465 -#define _POP_TOP_UNICODE_r32 1466 -#define _PUSH_EXC_INFO_r02 1467 -#define _PUSH_EXC_INFO_r12 1468 -#define _PUSH_EXC_INFO_r23 1469 -#define _PUSH_FRAME_r10 1470 -#define _PUSH_NULL_r01 1471 -#define _PUSH_NULL_r12 1472 -#define _PUSH_NULL_r23 1473 -#define _PUSH_NULL_CONDITIONAL_r00 1474 -#define _PUSH_TAGGED_ZERO_r01 1475 -#define _PUSH_TAGGED_ZERO_r12 1476 -#define _PUSH_TAGGED_ZERO_r23 1477 -#define _PY_FRAME_EX_r31 1478 -#define _PY_FRAME_GENERAL_r01 1479 -#define _PY_FRAME_KW_r11 1480 -#define _REPLACE_WITH_TRUE_r02 1481 -#define _REPLACE_WITH_TRUE_r12 1482 -#define _REPLACE_WITH_TRUE_r23 1483 -#define _RESUME_CHECK_r00 1484 -#define _RESUME_CHECK_r11 1485 -#define _RESUME_CHECK_r22 1486 -#define _RESUME_CHECK_r33 1487 -#define _RETURN_GENERATOR_r01 1488 -#define _RETURN_VALUE_r11 1489 -#define _RROT_3_r03 1490 -#define _RROT_3_r13 1491 -#define _RROT_3_r23 1492 -#define _RROT_3_r33 1493 -#define _SAVE_RETURN_OFFSET_r00 1494 -#define _SAVE_RETURN_OFFSET_r11 1495 -#define _SAVE_RETURN_OFFSET_r22 1496 -#define _SAVE_RETURN_OFFSET_r33 1497 -#define _SEND_r33 1498 -#define _SEND_GEN_FRAME_r33 1499 -#define _SETUP_ANNOTATIONS_r00 1500 -#define _SET_ADD_r10 1501 -#define _SET_FUNCTION_ATTRIBUTE_r01 1502 -#define _SET_FUNCTION_ATTRIBUTE_r11 1503 -#define _SET_FUNCTION_ATTRIBUTE_r21 1504 -#define _SET_FUNCTION_ATTRIBUTE_r32 1505 -#define _SET_IP_r00 1506 -#define _SET_IP_r11 1507 -#define _SET_IP_r22 1508 -#define _SET_IP_r33 1509 -#define _SET_UPDATE_r11 1510 -#define _SPILL_OR_RELOAD_r01 1511 -#define _SPILL_OR_RELOAD_r02 1512 -#define _SPILL_OR_RELOAD_r03 1513 -#define _SPILL_OR_RELOAD_r10 1514 -#define _SPILL_OR_RELOAD_r12 1515 -#define _SPILL_OR_RELOAD_r13 1516 -#define _SPILL_OR_RELOAD_r20 1517 -#define _SPILL_OR_RELOAD_r21 1518 -#define _SPILL_OR_RELOAD_r23 1519 -#define _SPILL_OR_RELOAD_r30 1520 -#define _SPILL_OR_RELOAD_r31 1521 -#define _SPILL_OR_RELOAD_r32 1522 -#define _START_EXECUTOR_r00 1523 -#define _STORE_ATTR_r20 1524 -#define _STORE_ATTR_INSTANCE_VALUE_r21 1525 -#define _STORE_ATTR_SLOT_r21 1526 -#define _STORE_ATTR_WITH_HINT_r21 1527 -#define _STORE_DEREF_r10 1528 -#define _STORE_FAST_LOAD_FAST_r11 1529 -#define _STORE_FAST_STORE_FAST_r20 1530 -#define _STORE_GLOBAL_r10 1531 -#define _STORE_NAME_r10 1532 -#define _STORE_SLICE_r30 1533 -#define _STORE_SUBSCR_r30 1534 -#define _STORE_SUBSCR_DICT_r31 1535 -#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1536 -#define _STORE_SUBSCR_LIST_INT_r32 1537 -#define _SWAP_r11 1538 -#define _SWAP_2_r02 1539 -#define _SWAP_2_r12 1540 -#define _SWAP_2_r22 1541 -#define _SWAP_2_r33 1542 -#define _SWAP_3_r03 1543 -#define _SWAP_3_r13 1544 -#define _SWAP_3_r23 1545 -#define _SWAP_3_r33 1546 -#define _SWAP_FAST_r01 1547 -#define _SWAP_FAST_r11 1548 -#define _SWAP_FAST_r22 1549 -#define _SWAP_FAST_r33 1550 -#define _SWAP_FAST_0_r01 1551 -#define _SWAP_FAST_0_r11 1552 -#define _SWAP_FAST_0_r22 1553 -#define _SWAP_FAST_0_r33 1554 -#define _SWAP_FAST_1_r01 1555 -#define _SWAP_FAST_1_r11 1556 -#define _SWAP_FAST_1_r22 1557 -#define _SWAP_FAST_1_r33 1558 -#define _SWAP_FAST_2_r01 1559 -#define _SWAP_FAST_2_r11 1560 -#define _SWAP_FAST_2_r22 1561 -#define _SWAP_FAST_2_r33 1562 -#define _SWAP_FAST_3_r01 1563 -#define _SWAP_FAST_3_r11 1564 -#define _SWAP_FAST_3_r22 1565 -#define _SWAP_FAST_3_r33 1566 -#define _SWAP_FAST_4_r01 1567 -#define _SWAP_FAST_4_r11 1568 -#define _SWAP_FAST_4_r22 1569 -#define _SWAP_FAST_4_r33 1570 -#define _SWAP_FAST_5_r01 1571 -#define _SWAP_FAST_5_r11 1572 -#define _SWAP_FAST_5_r22 1573 -#define _SWAP_FAST_5_r33 1574 -#define _SWAP_FAST_6_r01 1575 -#define _SWAP_FAST_6_r11 1576 -#define _SWAP_FAST_6_r22 1577 -#define _SWAP_FAST_6_r33 1578 -#define _SWAP_FAST_7_r01 1579 -#define _SWAP_FAST_7_r11 1580 -#define _SWAP_FAST_7_r22 1581 -#define _SWAP_FAST_7_r33 1582 -#define _TIER2_RESUME_CHECK_r00 1583 -#define _TIER2_RESUME_CHECK_r11 1584 -#define _TIER2_RESUME_CHECK_r22 1585 -#define _TIER2_RESUME_CHECK_r33 1586 -#define _TO_BOOL_r11 1587 -#define _TO_BOOL_BOOL_r01 1588 -#define _TO_BOOL_BOOL_r11 1589 -#define _TO_BOOL_BOOL_r22 1590 -#define _TO_BOOL_BOOL_r33 1591 -#define _TO_BOOL_INT_r02 1592 -#define _TO_BOOL_INT_r12 1593 -#define _TO_BOOL_INT_r23 1594 -#define _TO_BOOL_LIST_r02 1595 -#define _TO_BOOL_LIST_r12 1596 -#define _TO_BOOL_LIST_r23 1597 -#define _TO_BOOL_NONE_r01 1598 -#define _TO_BOOL_NONE_r11 1599 -#define _TO_BOOL_NONE_r22 1600 -#define _TO_BOOL_NONE_r33 1601 -#define _TO_BOOL_STR_r02 1602 -#define _TO_BOOL_STR_r12 1603 -#define _TO_BOOL_STR_r23 1604 -#define _TRACE_RECORD_r00 1605 -#define _UNARY_INVERT_r12 1606 -#define _UNARY_NEGATIVE_r12 1607 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1608 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1609 -#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1610 -#define _UNARY_NOT_r01 1611 -#define _UNARY_NOT_r11 1612 -#define _UNARY_NOT_r22 1613 -#define _UNARY_NOT_r33 1614 -#define _UNPACK_EX_r10 1615 -#define _UNPACK_SEQUENCE_r10 1616 -#define _UNPACK_SEQUENCE_LIST_r10 1617 -#define _UNPACK_SEQUENCE_TUPLE_r10 1618 -#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1619 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1620 -#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1621 -#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1622 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1623 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1624 -#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1625 -#define _WITH_EXCEPT_START_r33 1626 -#define _YIELD_VALUE_r11 1627 -#define MAX_UOP_REGS_ID 1627 +#define _YIELD_VALUE 648 +#define MAX_UOP_ID 648 +#define _ALLOCATE_OBJECT_r00 649 +#define _BINARY_OP_r23 650 +#define _BINARY_OP_ADD_FLOAT_r03 651 +#define _BINARY_OP_ADD_FLOAT_r13 652 +#define _BINARY_OP_ADD_FLOAT_r23 653 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r03 654 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r13 655 +#define _BINARY_OP_ADD_FLOAT_INPLACE_r23 656 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r03 657 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r13 658 +#define _BINARY_OP_ADD_FLOAT_INPLACE_RIGHT_r23 659 +#define _BINARY_OP_ADD_INT_r03 660 +#define _BINARY_OP_ADD_INT_r13 661 +#define _BINARY_OP_ADD_INT_r23 662 +#define _BINARY_OP_ADD_INT_INPLACE_r03 663 +#define _BINARY_OP_ADD_INT_INPLACE_r13 664 +#define _BINARY_OP_ADD_INT_INPLACE_r23 665 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r03 666 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r13 667 +#define _BINARY_OP_ADD_INT_INPLACE_RIGHT_r23 668 +#define _BINARY_OP_ADD_UNICODE_r03 669 +#define _BINARY_OP_ADD_UNICODE_r13 670 +#define _BINARY_OP_ADD_UNICODE_r23 671 +#define _BINARY_OP_EXTEND_r23 672 +#define _BINARY_OP_INPLACE_ADD_UNICODE_r21 673 +#define _BINARY_OP_MULTIPLY_FLOAT_r03 674 +#define _BINARY_OP_MULTIPLY_FLOAT_r13 675 +#define _BINARY_OP_MULTIPLY_FLOAT_r23 676 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r03 677 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r13 678 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_r23 679 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r03 680 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r13 681 +#define _BINARY_OP_MULTIPLY_FLOAT_INPLACE_RIGHT_r23 682 +#define _BINARY_OP_MULTIPLY_INT_r03 683 +#define _BINARY_OP_MULTIPLY_INT_r13 684 +#define _BINARY_OP_MULTIPLY_INT_r23 685 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r03 686 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r13 687 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_r23 688 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r03 689 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r13 690 +#define _BINARY_OP_MULTIPLY_INT_INPLACE_RIGHT_r23 691 +#define _BINARY_OP_SUBSCR_CHECK_FUNC_r23 692 +#define _BINARY_OP_SUBSCR_DICT_r23 693 +#define _BINARY_OP_SUBSCR_DICT_KNOWN_HASH_r23 694 +#define _BINARY_OP_SUBSCR_INIT_CALL_r01 695 +#define _BINARY_OP_SUBSCR_INIT_CALL_r11 696 +#define _BINARY_OP_SUBSCR_INIT_CALL_r21 697 +#define _BINARY_OP_SUBSCR_INIT_CALL_r31 698 +#define _BINARY_OP_SUBSCR_LIST_INT_r23 699 +#define _BINARY_OP_SUBSCR_LIST_SLICE_r23 700 +#define _BINARY_OP_SUBSCR_STR_INT_r23 701 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r03 702 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r13 703 +#define _BINARY_OP_SUBSCR_TUPLE_INT_r23 704 +#define _BINARY_OP_SUBSCR_USTR_INT_r23 705 +#define _BINARY_OP_SUBTRACT_FLOAT_r03 706 +#define _BINARY_OP_SUBTRACT_FLOAT_r13 707 +#define _BINARY_OP_SUBTRACT_FLOAT_r23 708 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r03 709 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r13 710 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_r23 711 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r03 712 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r13 713 +#define _BINARY_OP_SUBTRACT_FLOAT_INPLACE_RIGHT_r23 714 +#define _BINARY_OP_SUBTRACT_INT_r03 715 +#define _BINARY_OP_SUBTRACT_INT_r13 716 +#define _BINARY_OP_SUBTRACT_INT_r23 717 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r03 718 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r13 719 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_r23 720 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r03 721 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r13 722 +#define _BINARY_OP_SUBTRACT_INT_INPLACE_RIGHT_r23 723 +#define _BINARY_OP_TRUEDIV_FLOAT_r23 724 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r03 725 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r13 726 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_r23 727 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r03 728 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r13 729 +#define _BINARY_OP_TRUEDIV_FLOAT_INPLACE_RIGHT_r23 730 +#define _BINARY_SLICE_r31 731 +#define _BUILD_INTERPOLATION_r01 732 +#define _BUILD_LIST_r01 733 +#define _BUILD_MAP_r01 734 +#define _BUILD_SET_r01 735 +#define _BUILD_SLICE_r01 736 +#define _BUILD_STRING_r01 737 +#define _BUILD_TEMPLATE_r21 738 +#define _BUILD_TUPLE_r01 739 +#define _CALL_BUILTIN_CLASS_r00 740 +#define _CALL_BUILTIN_FAST_r00 741 +#define _CALL_BUILTIN_FAST_WITH_KEYWORDS_r00 742 +#define _CALL_BUILTIN_O_r03 743 +#define _CALL_FUNCTION_EX_NON_PY_GENERAL_r31 744 +#define _CALL_INTRINSIC_1_r12 745 +#define _CALL_INTRINSIC_2_r23 746 +#define _CALL_ISINSTANCE_r31 747 +#define _CALL_KW_NON_PY_r11 748 +#define _CALL_LEN_r33 749 +#define _CALL_LIST_APPEND_r03 750 +#define _CALL_LIST_APPEND_r13 751 +#define _CALL_LIST_APPEND_r23 752 +#define _CALL_LIST_APPEND_r33 753 +#define _CALL_METHOD_DESCRIPTOR_FAST_r00 754 +#define _CALL_METHOD_DESCRIPTOR_FAST_INLINE_r00 755 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 756 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_INLINE_r00 757 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_r03 758 +#define _CALL_METHOD_DESCRIPTOR_NOARGS_INLINE_r03 759 +#define _CALL_METHOD_DESCRIPTOR_O_r03 760 +#define _CALL_METHOD_DESCRIPTOR_O_INLINE_r03 761 +#define _CALL_NON_PY_GENERAL_r01 762 +#define _CALL_STR_1_r32 763 +#define _CALL_TUPLE_1_r32 764 +#define _CALL_TYPE_1_r02 765 +#define _CALL_TYPE_1_r12 766 +#define _CALL_TYPE_1_r22 767 +#define _CALL_TYPE_1_r32 768 +#define _CHECK_ATTR_CLASS_r01 769 +#define _CHECK_ATTR_CLASS_r11 770 +#define _CHECK_ATTR_CLASS_r22 771 +#define _CHECK_ATTR_CLASS_r33 772 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r01 773 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r11 774 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r22 775 +#define _CHECK_ATTR_METHOD_LAZY_DICT_r33 776 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS_r00 777 +#define _CHECK_EG_MATCH_r22 778 +#define _CHECK_EXC_MATCH_r22 779 +#define _CHECK_FUNCTION_EXACT_ARGS_r00 780 +#define _CHECK_FUNCTION_VERSION_r00 781 +#define _CHECK_FUNCTION_VERSION_INLINE_r00 782 +#define _CHECK_FUNCTION_VERSION_INLINE_r11 783 +#define _CHECK_FUNCTION_VERSION_INLINE_r22 784 +#define _CHECK_FUNCTION_VERSION_INLINE_r33 785 +#define _CHECK_FUNCTION_VERSION_KW_r11 786 +#define _CHECK_IS_NOT_PY_CALLABLE_r00 787 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r03 788 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r13 789 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r23 790 +#define _CHECK_IS_NOT_PY_CALLABLE_EX_r33 791 +#define _CHECK_IS_NOT_PY_CALLABLE_KW_r11 792 +#define _CHECK_IS_PY_CALLABLE_EX_r03 793 +#define _CHECK_IS_PY_CALLABLE_EX_r13 794 +#define _CHECK_IS_PY_CALLABLE_EX_r23 795 +#define _CHECK_IS_PY_CALLABLE_EX_r33 796 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r01 797 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r11 798 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r22 799 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES_r33 800 +#define _CHECK_METHOD_VERSION_r00 801 +#define _CHECK_METHOD_VERSION_KW_r11 802 +#define _CHECK_OBJECT_r00 803 +#define _CHECK_PEP_523_r00 804 +#define _CHECK_PEP_523_r11 805 +#define _CHECK_PEP_523_r22 806 +#define _CHECK_PEP_523_r33 807 +#define _CHECK_PERIODIC_r00 808 +#define _CHECK_PERIODIC_AT_END_r00 809 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM_r00 810 +#define _CHECK_RECURSION_LIMIT_r00 811 +#define _CHECK_RECURSION_LIMIT_r11 812 +#define _CHECK_RECURSION_LIMIT_r22 813 +#define _CHECK_RECURSION_LIMIT_r33 814 +#define _CHECK_RECURSION_REMAINING_r00 815 +#define _CHECK_RECURSION_REMAINING_r11 816 +#define _CHECK_RECURSION_REMAINING_r22 817 +#define _CHECK_RECURSION_REMAINING_r33 818 +#define _CHECK_STACK_SPACE_r00 819 +#define _CHECK_STACK_SPACE_OPERAND_r00 820 +#define _CHECK_STACK_SPACE_OPERAND_r11 821 +#define _CHECK_STACK_SPACE_OPERAND_r22 822 +#define _CHECK_STACK_SPACE_OPERAND_r33 823 +#define _CHECK_VALIDITY_r00 824 +#define _CHECK_VALIDITY_r11 825 +#define _CHECK_VALIDITY_r22 826 +#define _CHECK_VALIDITY_r33 827 +#define _COLD_DYNAMIC_EXIT_r00 828 +#define _COLD_EXIT_r00 829 +#define _COMPARE_OP_r21 830 +#define _COMPARE_OP_FLOAT_r03 831 +#define _COMPARE_OP_FLOAT_r13 832 +#define _COMPARE_OP_FLOAT_r23 833 +#define _COMPARE_OP_INT_r23 834 +#define _COMPARE_OP_STR_r23 835 +#define _CONTAINS_OP_r23 836 +#define _CONTAINS_OP_DICT_r23 837 +#define _CONTAINS_OP_SET_r23 838 +#define _CONVERT_VALUE_r11 839 +#define _COPY_r01 840 +#define _COPY_1_r02 841 +#define _COPY_1_r12 842 +#define _COPY_1_r23 843 +#define _COPY_2_r03 844 +#define _COPY_2_r13 845 +#define _COPY_2_r23 846 +#define _COPY_3_r03 847 +#define _COPY_3_r13 848 +#define _COPY_3_r23 849 +#define _COPY_3_r33 850 +#define _COPY_FREE_VARS_r00 851 +#define _COPY_FREE_VARS_r11 852 +#define _COPY_FREE_VARS_r22 853 +#define _COPY_FREE_VARS_r33 854 +#define _CREATE_INIT_FRAME_r01 855 +#define _DELETE_ATTR_r10 856 +#define _DELETE_DEREF_r00 857 +#define _DELETE_FAST_r00 858 +#define _DELETE_GLOBAL_r00 859 +#define _DELETE_NAME_r00 860 +#define _DELETE_SUBSCR_r20 861 +#define _DEOPT_r00 862 +#define _DEOPT_r10 863 +#define _DEOPT_r20 864 +#define _DEOPT_r30 865 +#define _DICT_MERGE_r11 866 +#define _DICT_UPDATE_r11 867 +#define _DO_CALL_r01 868 +#define _DO_CALL_FUNCTION_EX_r31 869 +#define _DO_CALL_KW_r11 870 +#define _DYNAMIC_EXIT_r00 871 +#define _DYNAMIC_EXIT_r10 872 +#define _DYNAMIC_EXIT_r20 873 +#define _DYNAMIC_EXIT_r30 874 +#define _END_FOR_r10 875 +#define _END_SEND_r31 876 +#define _ERROR_POP_N_r00 877 +#define _EXIT_INIT_CHECK_r10 878 +#define _EXIT_TRACE_r00 879 +#define _EXIT_TRACE_r10 880 +#define _EXIT_TRACE_r20 881 +#define _EXIT_TRACE_r30 882 +#define _EXPAND_METHOD_r00 883 +#define _EXPAND_METHOD_KW_r11 884 +#define _FATAL_ERROR_r00 885 +#define _FATAL_ERROR_r11 886 +#define _FATAL_ERROR_r22 887 +#define _FATAL_ERROR_r33 888 +#define _FORMAT_SIMPLE_r11 889 +#define _FORMAT_WITH_SPEC_r21 890 +#define _FOR_ITER_r23 891 +#define _FOR_ITER_GEN_FRAME_r03 892 +#define _FOR_ITER_GEN_FRAME_r13 893 +#define _FOR_ITER_GEN_FRAME_r23 894 +#define _FOR_ITER_TIER_TWO_r23 895 +#define _FOR_ITER_VIRTUAL_r23 896 +#define _FOR_ITER_VIRTUAL_TIER_TWO_r23 897 +#define _GET_AITER_r11 898 +#define _GET_ANEXT_r12 899 +#define _GET_AWAITABLE_r11 900 +#define _GET_ITER_r12 901 +#define _GET_ITER_TRAD_r12 902 +#define _GET_LEN_r12 903 +#define _GUARD_BINARY_OP_EXTEND_r22 904 +#define _GUARD_BINARY_OP_EXTEND_LHS_r02 905 +#define _GUARD_BINARY_OP_EXTEND_LHS_r12 906 +#define _GUARD_BINARY_OP_EXTEND_LHS_r22 907 +#define _GUARD_BINARY_OP_EXTEND_LHS_r33 908 +#define _GUARD_BINARY_OP_EXTEND_RHS_r02 909 +#define _GUARD_BINARY_OP_EXTEND_RHS_r12 910 +#define _GUARD_BINARY_OP_EXTEND_RHS_r22 911 +#define _GUARD_BINARY_OP_EXTEND_RHS_r33 912 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r02 913 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12 914 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22 915 +#define _GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33 916 +#define _GUARD_BIT_IS_SET_POP_r00 917 +#define _GUARD_BIT_IS_SET_POP_r10 918 +#define _GUARD_BIT_IS_SET_POP_r21 919 +#define _GUARD_BIT_IS_SET_POP_r32 920 +#define _GUARD_BIT_IS_SET_POP_4_r00 921 +#define _GUARD_BIT_IS_SET_POP_4_r10 922 +#define _GUARD_BIT_IS_SET_POP_4_r21 923 +#define _GUARD_BIT_IS_SET_POP_4_r32 924 +#define _GUARD_BIT_IS_SET_POP_5_r00 925 +#define _GUARD_BIT_IS_SET_POP_5_r10 926 +#define _GUARD_BIT_IS_SET_POP_5_r21 927 +#define _GUARD_BIT_IS_SET_POP_5_r32 928 +#define _GUARD_BIT_IS_SET_POP_6_r00 929 +#define _GUARD_BIT_IS_SET_POP_6_r10 930 +#define _GUARD_BIT_IS_SET_POP_6_r21 931 +#define _GUARD_BIT_IS_SET_POP_6_r32 932 +#define _GUARD_BIT_IS_SET_POP_7_r00 933 +#define _GUARD_BIT_IS_SET_POP_7_r10 934 +#define _GUARD_BIT_IS_SET_POP_7_r21 935 +#define _GUARD_BIT_IS_SET_POP_7_r32 936 +#define _GUARD_BIT_IS_UNSET_POP_r00 937 +#define _GUARD_BIT_IS_UNSET_POP_r10 938 +#define _GUARD_BIT_IS_UNSET_POP_r21 939 +#define _GUARD_BIT_IS_UNSET_POP_r32 940 +#define _GUARD_BIT_IS_UNSET_POP_4_r00 941 +#define _GUARD_BIT_IS_UNSET_POP_4_r10 942 +#define _GUARD_BIT_IS_UNSET_POP_4_r21 943 +#define _GUARD_BIT_IS_UNSET_POP_4_r32 944 +#define _GUARD_BIT_IS_UNSET_POP_5_r00 945 +#define _GUARD_BIT_IS_UNSET_POP_5_r10 946 +#define _GUARD_BIT_IS_UNSET_POP_5_r21 947 +#define _GUARD_BIT_IS_UNSET_POP_5_r32 948 +#define _GUARD_BIT_IS_UNSET_POP_6_r00 949 +#define _GUARD_BIT_IS_UNSET_POP_6_r10 950 +#define _GUARD_BIT_IS_UNSET_POP_6_r21 951 +#define _GUARD_BIT_IS_UNSET_POP_6_r32 952 +#define _GUARD_BIT_IS_UNSET_POP_7_r00 953 +#define _GUARD_BIT_IS_UNSET_POP_7_r10 954 +#define _GUARD_BIT_IS_UNSET_POP_7_r21 955 +#define _GUARD_BIT_IS_UNSET_POP_7_r32 956 +#define _GUARD_CALLABLE_BUILTIN_CLASS_r00 957 +#define _GUARD_CALLABLE_BUILTIN_FAST_r00 958 +#define _GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS_r00 959 +#define _GUARD_CALLABLE_BUILTIN_O_r00 960 +#define _GUARD_CALLABLE_ISINSTANCE_r03 961 +#define _GUARD_CALLABLE_ISINSTANCE_r13 962 +#define _GUARD_CALLABLE_ISINSTANCE_r23 963 +#define _GUARD_CALLABLE_ISINSTANCE_r33 964 +#define _GUARD_CALLABLE_LEN_r03 965 +#define _GUARD_CALLABLE_LEN_r13 966 +#define _GUARD_CALLABLE_LEN_r23 967 +#define _GUARD_CALLABLE_LEN_r33 968 +#define _GUARD_CALLABLE_LIST_APPEND_r03 969 +#define _GUARD_CALLABLE_LIST_APPEND_r13 970 +#define _GUARD_CALLABLE_LIST_APPEND_r23 971 +#define _GUARD_CALLABLE_LIST_APPEND_r33 972 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_r00 973 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r00 974 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_NOARGS_r00 975 +#define _GUARD_CALLABLE_METHOD_DESCRIPTOR_O_r00 976 +#define _GUARD_CALLABLE_STR_1_r03 977 +#define _GUARD_CALLABLE_STR_1_r13 978 +#define _GUARD_CALLABLE_STR_1_r23 979 +#define _GUARD_CALLABLE_STR_1_r33 980 +#define _GUARD_CALLABLE_TUPLE_1_r03 981 +#define _GUARD_CALLABLE_TUPLE_1_r13 982 +#define _GUARD_CALLABLE_TUPLE_1_r23 983 +#define _GUARD_CALLABLE_TUPLE_1_r33 984 +#define _GUARD_CALLABLE_TYPE_1_r03 985 +#define _GUARD_CALLABLE_TYPE_1_r13 986 +#define _GUARD_CALLABLE_TYPE_1_r23 987 +#define _GUARD_CALLABLE_TYPE_1_r33 988 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r00 989 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r11 990 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r22 991 +#define _GUARD_CODE_VERSION_RETURN_GENERATOR_r33 992 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r00 993 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r11 994 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r22 995 +#define _GUARD_CODE_VERSION_RETURN_VALUE_r33 996 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r00 997 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r11 998 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r22 999 +#define _GUARD_CODE_VERSION_YIELD_VALUE_r33 1000 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r00 1001 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r11 1002 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r22 1003 +#define _GUARD_CODE_VERSION__PUSH_FRAME_r33 1004 +#define _GUARD_DORV_NO_DICT_r01 1005 +#define _GUARD_DORV_NO_DICT_r11 1006 +#define _GUARD_DORV_NO_DICT_r22 1007 +#define _GUARD_DORV_NO_DICT_r33 1008 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r01 1009 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r11 1010 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r22 1011 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT_r33 1012 +#define _GUARD_GLOBALS_VERSION_r00 1013 +#define _GUARD_GLOBALS_VERSION_r11 1014 +#define _GUARD_GLOBALS_VERSION_r22 1015 +#define _GUARD_GLOBALS_VERSION_r33 1016 +#define _GUARD_IP_RETURN_GENERATOR_r00 1017 +#define _GUARD_IP_RETURN_GENERATOR_r11 1018 +#define _GUARD_IP_RETURN_GENERATOR_r22 1019 +#define _GUARD_IP_RETURN_GENERATOR_r33 1020 +#define _GUARD_IP_RETURN_VALUE_r00 1021 +#define _GUARD_IP_RETURN_VALUE_r11 1022 +#define _GUARD_IP_RETURN_VALUE_r22 1023 +#define _GUARD_IP_RETURN_VALUE_r33 1024 +#define _GUARD_IP_YIELD_VALUE_r00 1025 +#define _GUARD_IP_YIELD_VALUE_r11 1026 +#define _GUARD_IP_YIELD_VALUE_r22 1027 +#define _GUARD_IP_YIELD_VALUE_r33 1028 +#define _GUARD_IP__PUSH_FRAME_r00 1029 +#define _GUARD_IP__PUSH_FRAME_r11 1030 +#define _GUARD_IP__PUSH_FRAME_r22 1031 +#define _GUARD_IP__PUSH_FRAME_r33 1032 +#define _GUARD_IS_FALSE_POP_r00 1033 +#define _GUARD_IS_FALSE_POP_r10 1034 +#define _GUARD_IS_FALSE_POP_r21 1035 +#define _GUARD_IS_FALSE_POP_r32 1036 +#define _GUARD_IS_NONE_POP_r00 1037 +#define _GUARD_IS_NONE_POP_r10 1038 +#define _GUARD_IS_NONE_POP_r21 1039 +#define _GUARD_IS_NONE_POP_r32 1040 +#define _GUARD_IS_NOT_NONE_POP_r10 1041 +#define _GUARD_IS_TRUE_POP_r00 1042 +#define _GUARD_IS_TRUE_POP_r10 1043 +#define _GUARD_IS_TRUE_POP_r21 1044 +#define _GUARD_IS_TRUE_POP_r32 1045 +#define _GUARD_ITERATOR_r01 1046 +#define _GUARD_ITERATOR_r11 1047 +#define _GUARD_ITERATOR_r22 1048 +#define _GUARD_ITERATOR_r33 1049 +#define _GUARD_ITER_VIRTUAL_r01 1050 +#define _GUARD_ITER_VIRTUAL_r11 1051 +#define _GUARD_ITER_VIRTUAL_r22 1052 +#define _GUARD_ITER_VIRTUAL_r33 1053 +#define _GUARD_KEYS_VERSION_r01 1054 +#define _GUARD_KEYS_VERSION_r11 1055 +#define _GUARD_KEYS_VERSION_r22 1056 +#define _GUARD_KEYS_VERSION_r33 1057 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r03 1058 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r13 1059 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r23 1060 +#define _GUARD_LOAD_SUPER_ATTR_METHOD_r33 1061 +#define _GUARD_NOS_COMPACT_ASCII_r02 1062 +#define _GUARD_NOS_COMPACT_ASCII_r12 1063 +#define _GUARD_NOS_COMPACT_ASCII_r22 1064 +#define _GUARD_NOS_COMPACT_ASCII_r33 1065 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r03 1066 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r13 1067 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r23 1068 +#define _GUARD_NOS_DICT_STORE_SUBSCRIPT_r33 1069 +#define _GUARD_NOS_DICT_SUBSCRIPT_r02 1070 +#define _GUARD_NOS_DICT_SUBSCRIPT_r12 1071 +#define _GUARD_NOS_DICT_SUBSCRIPT_r22 1072 +#define _GUARD_NOS_DICT_SUBSCRIPT_r33 1073 +#define _GUARD_NOS_FLOAT_r02 1074 +#define _GUARD_NOS_FLOAT_r12 1075 +#define _GUARD_NOS_FLOAT_r22 1076 +#define _GUARD_NOS_FLOAT_r33 1077 +#define _GUARD_NOS_INT_r02 1078 +#define _GUARD_NOS_INT_r12 1079 +#define _GUARD_NOS_INT_r22 1080 +#define _GUARD_NOS_INT_r33 1081 +#define _GUARD_NOS_ITER_VIRTUAL_r02 1082 +#define _GUARD_NOS_ITER_VIRTUAL_r12 1083 +#define _GUARD_NOS_ITER_VIRTUAL_r22 1084 +#define _GUARD_NOS_ITER_VIRTUAL_r33 1085 +#define _GUARD_NOS_LIST_r02 1086 +#define _GUARD_NOS_LIST_r12 1087 +#define _GUARD_NOS_LIST_r22 1088 +#define _GUARD_NOS_LIST_r33 1089 +#define _GUARD_NOS_NOT_NULL_r02 1090 +#define _GUARD_NOS_NOT_NULL_r12 1091 +#define _GUARD_NOS_NOT_NULL_r22 1092 +#define _GUARD_NOS_NOT_NULL_r33 1093 +#define _GUARD_NOS_NULL_r02 1094 +#define _GUARD_NOS_NULL_r12 1095 +#define _GUARD_NOS_NULL_r22 1096 +#define _GUARD_NOS_NULL_r33 1097 +#define _GUARD_NOS_OVERFLOWED_r02 1098 +#define _GUARD_NOS_OVERFLOWED_r12 1099 +#define _GUARD_NOS_OVERFLOWED_r22 1100 +#define _GUARD_NOS_OVERFLOWED_r33 1101 +#define _GUARD_NOS_TUPLE_r02 1102 +#define _GUARD_NOS_TUPLE_r12 1103 +#define _GUARD_NOS_TUPLE_r22 1104 +#define _GUARD_NOS_TUPLE_r33 1105 +#define _GUARD_NOS_TYPE_VERSION_r02 1106 +#define _GUARD_NOS_TYPE_VERSION_r12 1107 +#define _GUARD_NOS_TYPE_VERSION_r22 1108 +#define _GUARD_NOS_TYPE_VERSION_r33 1109 +#define _GUARD_NOS_UNICODE_r02 1110 +#define _GUARD_NOS_UNICODE_r12 1111 +#define _GUARD_NOS_UNICODE_r22 1112 +#define _GUARD_NOS_UNICODE_r33 1113 +#define _GUARD_NOT_EXHAUSTED_LIST_r02 1114 +#define _GUARD_NOT_EXHAUSTED_LIST_r12 1115 +#define _GUARD_NOT_EXHAUSTED_LIST_r22 1116 +#define _GUARD_NOT_EXHAUSTED_LIST_r33 1117 +#define _GUARD_NOT_EXHAUSTED_RANGE_r02 1118 +#define _GUARD_NOT_EXHAUSTED_RANGE_r12 1119 +#define _GUARD_NOT_EXHAUSTED_RANGE_r22 1120 +#define _GUARD_NOT_EXHAUSTED_RANGE_r33 1121 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r02 1122 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r12 1123 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r22 1124 +#define _GUARD_NOT_EXHAUSTED_TUPLE_r33 1125 +#define _GUARD_THIRD_NULL_r03 1126 +#define _GUARD_THIRD_NULL_r13 1127 +#define _GUARD_THIRD_NULL_r23 1128 +#define _GUARD_THIRD_NULL_r33 1129 +#define _GUARD_TOS_ANY_DICT_r01 1130 +#define _GUARD_TOS_ANY_DICT_r11 1131 +#define _GUARD_TOS_ANY_DICT_r22 1132 +#define _GUARD_TOS_ANY_DICT_r33 1133 +#define _GUARD_TOS_ANY_SET_r01 1134 +#define _GUARD_TOS_ANY_SET_r11 1135 +#define _GUARD_TOS_ANY_SET_r22 1136 +#define _GUARD_TOS_ANY_SET_r33 1137 +#define _GUARD_TOS_DICT_r01 1138 +#define _GUARD_TOS_DICT_r11 1139 +#define _GUARD_TOS_DICT_r22 1140 +#define _GUARD_TOS_DICT_r33 1141 +#define _GUARD_TOS_FLOAT_r01 1142 +#define _GUARD_TOS_FLOAT_r11 1143 +#define _GUARD_TOS_FLOAT_r22 1144 +#define _GUARD_TOS_FLOAT_r33 1145 +#define _GUARD_TOS_FROZENDICT_r01 1146 +#define _GUARD_TOS_FROZENDICT_r11 1147 +#define _GUARD_TOS_FROZENDICT_r22 1148 +#define _GUARD_TOS_FROZENDICT_r33 1149 +#define _GUARD_TOS_FROZENSET_r01 1150 +#define _GUARD_TOS_FROZENSET_r11 1151 +#define _GUARD_TOS_FROZENSET_r22 1152 +#define _GUARD_TOS_FROZENSET_r33 1153 +#define _GUARD_TOS_INT_r01 1154 +#define _GUARD_TOS_INT_r11 1155 +#define _GUARD_TOS_INT_r22 1156 +#define _GUARD_TOS_INT_r33 1157 +#define _GUARD_TOS_LIST_r01 1158 +#define _GUARD_TOS_LIST_r11 1159 +#define _GUARD_TOS_LIST_r22 1160 +#define _GUARD_TOS_LIST_r33 1161 +#define _GUARD_TOS_OVERFLOWED_r01 1162 +#define _GUARD_TOS_OVERFLOWED_r11 1163 +#define _GUARD_TOS_OVERFLOWED_r22 1164 +#define _GUARD_TOS_OVERFLOWED_r33 1165 +#define _GUARD_TOS_SET_r01 1166 +#define _GUARD_TOS_SET_r11 1167 +#define _GUARD_TOS_SET_r22 1168 +#define _GUARD_TOS_SET_r33 1169 +#define _GUARD_TOS_SLICE_r01 1170 +#define _GUARD_TOS_SLICE_r11 1171 +#define _GUARD_TOS_SLICE_r22 1172 +#define _GUARD_TOS_SLICE_r33 1173 +#define _GUARD_TOS_TUPLE_r01 1174 +#define _GUARD_TOS_TUPLE_r11 1175 +#define _GUARD_TOS_TUPLE_r22 1176 +#define _GUARD_TOS_TUPLE_r33 1177 +#define _GUARD_TOS_UNICODE_r01 1178 +#define _GUARD_TOS_UNICODE_r11 1179 +#define _GUARD_TOS_UNICODE_r22 1180 +#define _GUARD_TOS_UNICODE_r33 1181 +#define _GUARD_TYPE_r01 1182 +#define _GUARD_TYPE_r11 1183 +#define _GUARD_TYPE_r22 1184 +#define _GUARD_TYPE_r33 1185 +#define _GUARD_TYPE_ITER_r02 1186 +#define _GUARD_TYPE_ITER_r12 1187 +#define _GUARD_TYPE_ITER_r22 1188 +#define _GUARD_TYPE_ITER_r33 1189 +#define _GUARD_TYPE_VERSION_r01 1190 +#define _GUARD_TYPE_VERSION_r11 1191 +#define _GUARD_TYPE_VERSION_r22 1192 +#define _GUARD_TYPE_VERSION_r33 1193 +#define _GUARD_TYPE_VERSION_LOCKED_r01 1194 +#define _GUARD_TYPE_VERSION_LOCKED_r11 1195 +#define _GUARD_TYPE_VERSION_LOCKED_r22 1196 +#define _GUARD_TYPE_VERSION_LOCKED_r33 1197 +#define _HANDLE_PENDING_AND_DEOPT_r00 1198 +#define _HANDLE_PENDING_AND_DEOPT_r10 1199 +#define _HANDLE_PENDING_AND_DEOPT_r20 1200 +#define _HANDLE_PENDING_AND_DEOPT_r30 1201 +#define _IMPORT_FROM_r12 1202 +#define _IMPORT_NAME_r21 1203 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS_r00 1204 +#define _INIT_CALL_PY_EXACT_ARGS_r01 1205 +#define _INIT_CALL_PY_EXACT_ARGS_0_r01 1206 +#define _INIT_CALL_PY_EXACT_ARGS_1_r01 1207 +#define _INIT_CALL_PY_EXACT_ARGS_2_r01 1208 +#define _INIT_CALL_PY_EXACT_ARGS_3_r01 1209 +#define _INIT_CALL_PY_EXACT_ARGS_4_r01 1210 +#define _INSERT_NULL_r10 1211 +#define _INSTRUMENTED_FOR_ITER_r23 1212 +#define _INSTRUMENTED_INSTRUCTION_r00 1213 +#define _INSTRUMENTED_JUMP_FORWARD_r00 1214 +#define _INSTRUMENTED_JUMP_FORWARD_r11 1215 +#define _INSTRUMENTED_JUMP_FORWARD_r22 1216 +#define _INSTRUMENTED_JUMP_FORWARD_r33 1217 +#define _INSTRUMENTED_LINE_r00 1218 +#define _INSTRUMENTED_NOT_TAKEN_r00 1219 +#define _INSTRUMENTED_NOT_TAKEN_r11 1220 +#define _INSTRUMENTED_NOT_TAKEN_r22 1221 +#define _INSTRUMENTED_NOT_TAKEN_r33 1222 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r00 1223 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r10 1224 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r21 1225 +#define _INSTRUMENTED_POP_JUMP_IF_FALSE_r32 1226 +#define _INSTRUMENTED_POP_JUMP_IF_NONE_r10 1227 +#define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE_r10 1228 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r00 1229 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r10 1230 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r21 1231 +#define _INSTRUMENTED_POP_JUMP_IF_TRUE_r32 1232 +#define _IS_NONE_r11 1233 +#define _IS_OP_r03 1234 +#define _IS_OP_r13 1235 +#define _IS_OP_r23 1236 +#define _ITER_CHECK_LIST_r02 1237 +#define _ITER_CHECK_LIST_r12 1238 +#define _ITER_CHECK_LIST_r22 1239 +#define _ITER_CHECK_LIST_r33 1240 +#define _ITER_CHECK_RANGE_r02 1241 +#define _ITER_CHECK_RANGE_r12 1242 +#define _ITER_CHECK_RANGE_r22 1243 +#define _ITER_CHECK_RANGE_r33 1244 +#define _ITER_CHECK_TUPLE_r02 1245 +#define _ITER_CHECK_TUPLE_r12 1246 +#define _ITER_CHECK_TUPLE_r22 1247 +#define _ITER_CHECK_TUPLE_r33 1248 +#define _ITER_JUMP_LIST_r02 1249 +#define _ITER_JUMP_LIST_r12 1250 +#define _ITER_JUMP_LIST_r22 1251 +#define _ITER_JUMP_LIST_r33 1252 +#define _ITER_JUMP_RANGE_r02 1253 +#define _ITER_JUMP_RANGE_r12 1254 +#define _ITER_JUMP_RANGE_r22 1255 +#define _ITER_JUMP_RANGE_r33 1256 +#define _ITER_JUMP_TUPLE_r02 1257 +#define _ITER_JUMP_TUPLE_r12 1258 +#define _ITER_JUMP_TUPLE_r22 1259 +#define _ITER_JUMP_TUPLE_r33 1260 +#define _ITER_NEXT_INLINE_r23 1261 +#define _ITER_NEXT_LIST_r23 1262 +#define _ITER_NEXT_LIST_TIER_TWO_r23 1263 +#define _ITER_NEXT_RANGE_r03 1264 +#define _ITER_NEXT_RANGE_r13 1265 +#define _ITER_NEXT_RANGE_r23 1266 +#define _ITER_NEXT_TUPLE_r03 1267 +#define _ITER_NEXT_TUPLE_r13 1268 +#define _ITER_NEXT_TUPLE_r23 1269 +#define _JUMP_BACKWARD_NO_INTERRUPT_r00 1270 +#define _JUMP_BACKWARD_NO_INTERRUPT_r11 1271 +#define _JUMP_BACKWARD_NO_INTERRUPT_r22 1272 +#define _JUMP_BACKWARD_NO_INTERRUPT_r33 1273 +#define _JUMP_TO_TOP_r00 1274 +#define _LIST_APPEND_r10 1275 +#define _LIST_EXTEND_r11 1276 +#define _LOAD_ATTR_r10 1277 +#define _LOAD_ATTR_CLASS_r11 1278 +#define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME_r11 1279 +#define _LOAD_ATTR_INSTANCE_VALUE_r02 1280 +#define _LOAD_ATTR_INSTANCE_VALUE_r12 1281 +#define _LOAD_ATTR_INSTANCE_VALUE_r23 1282 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r02 1283 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r12 1284 +#define _LOAD_ATTR_METHOD_LAZY_DICT_r23 1285 +#define _LOAD_ATTR_METHOD_NO_DICT_r02 1286 +#define _LOAD_ATTR_METHOD_NO_DICT_r12 1287 +#define _LOAD_ATTR_METHOD_NO_DICT_r23 1288 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r02 1289 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r12 1290 +#define _LOAD_ATTR_METHOD_WITH_VALUES_r23 1291 +#define _LOAD_ATTR_MODULE_r12 1292 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11 1293 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1294 +#define _LOAD_ATTR_PROPERTY_FRAME_r01 1295 +#define _LOAD_ATTR_PROPERTY_FRAME_r11 1296 +#define _LOAD_ATTR_PROPERTY_FRAME_r22 1297 +#define _LOAD_ATTR_PROPERTY_FRAME_r33 1298 +#define _LOAD_ATTR_SLOT_r02 1299 +#define _LOAD_ATTR_SLOT_r12 1300 +#define _LOAD_ATTR_SLOT_r23 1301 +#define _LOAD_ATTR_WITH_HINT_r12 1302 +#define _LOAD_BUILD_CLASS_r01 1303 +#define _LOAD_BYTECODE_r00 1304 +#define _LOAD_COMMON_CONSTANT_r01 1305 +#define _LOAD_COMMON_CONSTANT_r12 1306 +#define _LOAD_COMMON_CONSTANT_r23 1307 +#define _LOAD_CONST_r01 1308 +#define _LOAD_CONST_r12 1309 +#define _LOAD_CONST_r23 1310 +#define _LOAD_CONST_INLINE_r01 1311 +#define _LOAD_CONST_INLINE_r12 1312 +#define _LOAD_CONST_INLINE_r23 1313 +#define _LOAD_CONST_INLINE_BORROW_r01 1314 +#define _LOAD_CONST_INLINE_BORROW_r12 1315 +#define _LOAD_CONST_INLINE_BORROW_r23 1316 +#define _LOAD_DEREF_r01 1317 +#define _LOAD_FAST_r01 1318 +#define _LOAD_FAST_r12 1319 +#define _LOAD_FAST_r23 1320 +#define _LOAD_FAST_0_r01 1321 +#define _LOAD_FAST_0_r12 1322 +#define _LOAD_FAST_0_r23 1323 +#define _LOAD_FAST_1_r01 1324 +#define _LOAD_FAST_1_r12 1325 +#define _LOAD_FAST_1_r23 1326 +#define _LOAD_FAST_2_r01 1327 +#define _LOAD_FAST_2_r12 1328 +#define _LOAD_FAST_2_r23 1329 +#define _LOAD_FAST_3_r01 1330 +#define _LOAD_FAST_3_r12 1331 +#define _LOAD_FAST_3_r23 1332 +#define _LOAD_FAST_4_r01 1333 +#define _LOAD_FAST_4_r12 1334 +#define _LOAD_FAST_4_r23 1335 +#define _LOAD_FAST_5_r01 1336 +#define _LOAD_FAST_5_r12 1337 +#define _LOAD_FAST_5_r23 1338 +#define _LOAD_FAST_6_r01 1339 +#define _LOAD_FAST_6_r12 1340 +#define _LOAD_FAST_6_r23 1341 +#define _LOAD_FAST_7_r01 1342 +#define _LOAD_FAST_7_r12 1343 +#define _LOAD_FAST_7_r23 1344 +#define _LOAD_FAST_AND_CLEAR_r01 1345 +#define _LOAD_FAST_AND_CLEAR_r12 1346 +#define _LOAD_FAST_AND_CLEAR_r23 1347 +#define _LOAD_FAST_BORROW_r01 1348 +#define _LOAD_FAST_BORROW_r12 1349 +#define _LOAD_FAST_BORROW_r23 1350 +#define _LOAD_FAST_BORROW_0_r01 1351 +#define _LOAD_FAST_BORROW_0_r12 1352 +#define _LOAD_FAST_BORROW_0_r23 1353 +#define _LOAD_FAST_BORROW_1_r01 1354 +#define _LOAD_FAST_BORROW_1_r12 1355 +#define _LOAD_FAST_BORROW_1_r23 1356 +#define _LOAD_FAST_BORROW_2_r01 1357 +#define _LOAD_FAST_BORROW_2_r12 1358 +#define _LOAD_FAST_BORROW_2_r23 1359 +#define _LOAD_FAST_BORROW_3_r01 1360 +#define _LOAD_FAST_BORROW_3_r12 1361 +#define _LOAD_FAST_BORROW_3_r23 1362 +#define _LOAD_FAST_BORROW_4_r01 1363 +#define _LOAD_FAST_BORROW_4_r12 1364 +#define _LOAD_FAST_BORROW_4_r23 1365 +#define _LOAD_FAST_BORROW_5_r01 1366 +#define _LOAD_FAST_BORROW_5_r12 1367 +#define _LOAD_FAST_BORROW_5_r23 1368 +#define _LOAD_FAST_BORROW_6_r01 1369 +#define _LOAD_FAST_BORROW_6_r12 1370 +#define _LOAD_FAST_BORROW_6_r23 1371 +#define _LOAD_FAST_BORROW_7_r01 1372 +#define _LOAD_FAST_BORROW_7_r12 1373 +#define _LOAD_FAST_BORROW_7_r23 1374 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r02 1375 +#define _LOAD_FAST_BORROW_LOAD_FAST_BORROW_r13 1376 +#define _LOAD_FAST_CHECK_r01 1377 +#define _LOAD_FAST_CHECK_r12 1378 +#define _LOAD_FAST_CHECK_r23 1379 +#define _LOAD_FAST_LOAD_FAST_r02 1380 +#define _LOAD_FAST_LOAD_FAST_r13 1381 +#define _LOAD_FROM_DICT_OR_DEREF_r11 1382 +#define _LOAD_FROM_DICT_OR_GLOBALS_r11 1383 +#define _LOAD_GLOBAL_r00 1384 +#define _LOAD_GLOBAL_BUILTINS_r01 1385 +#define _LOAD_GLOBAL_MODULE_r01 1386 +#define _LOAD_LOCALS_r01 1387 +#define _LOAD_LOCALS_r12 1388 +#define _LOAD_LOCALS_r23 1389 +#define _LOAD_NAME_r01 1390 +#define _LOAD_SMALL_INT_r01 1391 +#define _LOAD_SMALL_INT_r12 1392 +#define _LOAD_SMALL_INT_r23 1393 +#define _LOAD_SMALL_INT_0_r01 1394 +#define _LOAD_SMALL_INT_0_r12 1395 +#define _LOAD_SMALL_INT_0_r23 1396 +#define _LOAD_SMALL_INT_1_r01 1397 +#define _LOAD_SMALL_INT_1_r12 1398 +#define _LOAD_SMALL_INT_1_r23 1399 +#define _LOAD_SMALL_INT_2_r01 1400 +#define _LOAD_SMALL_INT_2_r12 1401 +#define _LOAD_SMALL_INT_2_r23 1402 +#define _LOAD_SMALL_INT_3_r01 1403 +#define _LOAD_SMALL_INT_3_r12 1404 +#define _LOAD_SMALL_INT_3_r23 1405 +#define _LOAD_SPECIAL_r00 1406 +#define _LOAD_SUPER_ATTR_ATTR_r31 1407 +#define _LOAD_SUPER_ATTR_METHOD_r32 1408 +#define _LOCK_OBJECT_r01 1409 +#define _LOCK_OBJECT_r11 1410 +#define _LOCK_OBJECT_r22 1411 +#define _LOCK_OBJECT_r33 1412 +#define _MAKE_CALLARGS_A_TUPLE_r33 1413 +#define _MAKE_CELL_r00 1414 +#define _MAKE_FUNCTION_r12 1415 +#define _MAKE_HEAP_SAFE_r01 1416 +#define _MAKE_HEAP_SAFE_r11 1417 +#define _MAKE_HEAP_SAFE_r22 1418 +#define _MAKE_HEAP_SAFE_r33 1419 +#define _MAKE_WARM_r00 1420 +#define _MAKE_WARM_r11 1421 +#define _MAKE_WARM_r22 1422 +#define _MAKE_WARM_r33 1423 +#define _MAP_ADD_r20 1424 +#define _MATCH_CLASS_r33 1425 +#define _MATCH_KEYS_r23 1426 +#define _MATCH_MAPPING_r02 1427 +#define _MATCH_MAPPING_r12 1428 +#define _MATCH_MAPPING_r23 1429 +#define _MATCH_SEQUENCE_r02 1430 +#define _MATCH_SEQUENCE_r12 1431 +#define _MATCH_SEQUENCE_r23 1432 +#define _MAYBE_EXPAND_METHOD_r00 1433 +#define _MAYBE_EXPAND_METHOD_KW_r11 1434 +#define _MONITOR_CALL_r00 1435 +#define _MONITOR_CALL_KW_r11 1436 +#define _MONITOR_JUMP_BACKWARD_r00 1437 +#define _MONITOR_JUMP_BACKWARD_r11 1438 +#define _MONITOR_JUMP_BACKWARD_r22 1439 +#define _MONITOR_JUMP_BACKWARD_r33 1440 +#define _MONITOR_RESUME_r00 1441 +#define _NOP_r00 1442 +#define _NOP_r11 1443 +#define _NOP_r22 1444 +#define _NOP_r33 1445 +#define _POP_EXCEPT_r10 1446 +#define _POP_ITER_r20 1447 +#define _POP_JUMP_IF_FALSE_r00 1448 +#define _POP_JUMP_IF_FALSE_r10 1449 +#define _POP_JUMP_IF_FALSE_r21 1450 +#define _POP_JUMP_IF_FALSE_r32 1451 +#define _POP_JUMP_IF_TRUE_r00 1452 +#define _POP_JUMP_IF_TRUE_r10 1453 +#define _POP_JUMP_IF_TRUE_r21 1454 +#define _POP_JUMP_IF_TRUE_r32 1455 +#define _POP_TOP_r10 1456 +#define _POP_TOP_FLOAT_r00 1457 +#define _POP_TOP_FLOAT_r10 1458 +#define _POP_TOP_FLOAT_r21 1459 +#define _POP_TOP_FLOAT_r32 1460 +#define _POP_TOP_INT_r00 1461 +#define _POP_TOP_INT_r10 1462 +#define _POP_TOP_INT_r21 1463 +#define _POP_TOP_INT_r32 1464 +#define _POP_TOP_NOP_r00 1465 +#define _POP_TOP_NOP_r10 1466 +#define _POP_TOP_NOP_r21 1467 +#define _POP_TOP_NOP_r32 1468 +#define _POP_TOP_OPARG_r00 1469 +#define _POP_TOP_UNICODE_r00 1470 +#define _POP_TOP_UNICODE_r10 1471 +#define _POP_TOP_UNICODE_r21 1472 +#define _POP_TOP_UNICODE_r32 1473 +#define _PUSH_EXC_INFO_r02 1474 +#define _PUSH_EXC_INFO_r12 1475 +#define _PUSH_EXC_INFO_r23 1476 +#define _PUSH_FRAME_r10 1477 +#define _PUSH_NULL_r01 1478 +#define _PUSH_NULL_r12 1479 +#define _PUSH_NULL_r23 1480 +#define _PUSH_NULL_CONDITIONAL_r00 1481 +#define _PUSH_TAGGED_ZERO_r01 1482 +#define _PUSH_TAGGED_ZERO_r12 1483 +#define _PUSH_TAGGED_ZERO_r23 1484 +#define _PY_FRAME_EX_r31 1485 +#define _PY_FRAME_GENERAL_r01 1486 +#define _PY_FRAME_KW_r11 1487 +#define _REPLACE_WITH_TRUE_r02 1488 +#define _REPLACE_WITH_TRUE_r12 1489 +#define _REPLACE_WITH_TRUE_r23 1490 +#define _RESUME_CHECK_r00 1491 +#define _RESUME_CHECK_r11 1492 +#define _RESUME_CHECK_r22 1493 +#define _RESUME_CHECK_r33 1494 +#define _RETURN_GENERATOR_r01 1495 +#define _RETURN_VALUE_r11 1496 +#define _RROT_3_r03 1497 +#define _RROT_3_r13 1498 +#define _RROT_3_r23 1499 +#define _RROT_3_r33 1500 +#define _SAVE_RETURN_OFFSET_r00 1501 +#define _SAVE_RETURN_OFFSET_r11 1502 +#define _SAVE_RETURN_OFFSET_r22 1503 +#define _SAVE_RETURN_OFFSET_r33 1504 +#define _SEND_r33 1505 +#define _SEND_GEN_FRAME_r33 1506 +#define _SETUP_ANNOTATIONS_r00 1507 +#define _SET_ADD_r10 1508 +#define _SET_FUNCTION_ATTRIBUTE_r01 1509 +#define _SET_FUNCTION_ATTRIBUTE_r11 1510 +#define _SET_FUNCTION_ATTRIBUTE_r21 1511 +#define _SET_FUNCTION_ATTRIBUTE_r32 1512 +#define _SET_IP_r00 1513 +#define _SET_IP_r11 1514 +#define _SET_IP_r22 1515 +#define _SET_IP_r33 1516 +#define _SET_UPDATE_r11 1517 +#define _SPILL_OR_RELOAD_r01 1518 +#define _SPILL_OR_RELOAD_r02 1519 +#define _SPILL_OR_RELOAD_r03 1520 +#define _SPILL_OR_RELOAD_r10 1521 +#define _SPILL_OR_RELOAD_r12 1522 +#define _SPILL_OR_RELOAD_r13 1523 +#define _SPILL_OR_RELOAD_r20 1524 +#define _SPILL_OR_RELOAD_r21 1525 +#define _SPILL_OR_RELOAD_r23 1526 +#define _SPILL_OR_RELOAD_r30 1527 +#define _SPILL_OR_RELOAD_r31 1528 +#define _SPILL_OR_RELOAD_r32 1529 +#define _START_EXECUTOR_r00 1530 +#define _STORE_ATTR_r20 1531 +#define _STORE_ATTR_INSTANCE_VALUE_r21 1532 +#define _STORE_ATTR_SLOT_r21 1533 +#define _STORE_ATTR_WITH_HINT_r21 1534 +#define _STORE_DEREF_r10 1535 +#define _STORE_FAST_LOAD_FAST_r11 1536 +#define _STORE_FAST_STORE_FAST_r20 1537 +#define _STORE_GLOBAL_r10 1538 +#define _STORE_NAME_r10 1539 +#define _STORE_SLICE_r30 1540 +#define _STORE_SUBSCR_r30 1541 +#define _STORE_SUBSCR_DICT_r31 1542 +#define _STORE_SUBSCR_DICT_KNOWN_HASH_r31 1543 +#define _STORE_SUBSCR_LIST_INT_r32 1544 +#define _SWAP_r11 1545 +#define _SWAP_2_r02 1546 +#define _SWAP_2_r12 1547 +#define _SWAP_2_r22 1548 +#define _SWAP_2_r33 1549 +#define _SWAP_3_r03 1550 +#define _SWAP_3_r13 1551 +#define _SWAP_3_r23 1552 +#define _SWAP_3_r33 1553 +#define _SWAP_FAST_r01 1554 +#define _SWAP_FAST_r11 1555 +#define _SWAP_FAST_r22 1556 +#define _SWAP_FAST_r33 1557 +#define _SWAP_FAST_0_r01 1558 +#define _SWAP_FAST_0_r11 1559 +#define _SWAP_FAST_0_r22 1560 +#define _SWAP_FAST_0_r33 1561 +#define _SWAP_FAST_1_r01 1562 +#define _SWAP_FAST_1_r11 1563 +#define _SWAP_FAST_1_r22 1564 +#define _SWAP_FAST_1_r33 1565 +#define _SWAP_FAST_2_r01 1566 +#define _SWAP_FAST_2_r11 1567 +#define _SWAP_FAST_2_r22 1568 +#define _SWAP_FAST_2_r33 1569 +#define _SWAP_FAST_3_r01 1570 +#define _SWAP_FAST_3_r11 1571 +#define _SWAP_FAST_3_r22 1572 +#define _SWAP_FAST_3_r33 1573 +#define _SWAP_FAST_4_r01 1574 +#define _SWAP_FAST_4_r11 1575 +#define _SWAP_FAST_4_r22 1576 +#define _SWAP_FAST_4_r33 1577 +#define _SWAP_FAST_5_r01 1578 +#define _SWAP_FAST_5_r11 1579 +#define _SWAP_FAST_5_r22 1580 +#define _SWAP_FAST_5_r33 1581 +#define _SWAP_FAST_6_r01 1582 +#define _SWAP_FAST_6_r11 1583 +#define _SWAP_FAST_6_r22 1584 +#define _SWAP_FAST_6_r33 1585 +#define _SWAP_FAST_7_r01 1586 +#define _SWAP_FAST_7_r11 1587 +#define _SWAP_FAST_7_r22 1588 +#define _SWAP_FAST_7_r33 1589 +#define _TIER2_RESUME_CHECK_r00 1590 +#define _TIER2_RESUME_CHECK_r11 1591 +#define _TIER2_RESUME_CHECK_r22 1592 +#define _TIER2_RESUME_CHECK_r33 1593 +#define _TO_BOOL_r11 1594 +#define _TO_BOOL_BOOL_r01 1595 +#define _TO_BOOL_BOOL_r11 1596 +#define _TO_BOOL_BOOL_r22 1597 +#define _TO_BOOL_BOOL_r33 1598 +#define _TO_BOOL_INT_r02 1599 +#define _TO_BOOL_INT_r12 1600 +#define _TO_BOOL_INT_r23 1601 +#define _TO_BOOL_LIST_r02 1602 +#define _TO_BOOL_LIST_r12 1603 +#define _TO_BOOL_LIST_r23 1604 +#define _TO_BOOL_NONE_r01 1605 +#define _TO_BOOL_NONE_r11 1606 +#define _TO_BOOL_NONE_r22 1607 +#define _TO_BOOL_NONE_r33 1608 +#define _TO_BOOL_STR_r02 1609 +#define _TO_BOOL_STR_r12 1610 +#define _TO_BOOL_STR_r23 1611 +#define _TRACE_RECORD_r00 1612 +#define _UNARY_INVERT_r12 1613 +#define _UNARY_NEGATIVE_r12 1614 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r02 1615 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r12 1616 +#define _UNARY_NEGATIVE_FLOAT_INPLACE_r23 1617 +#define _UNARY_NOT_r01 1618 +#define _UNARY_NOT_r11 1619 +#define _UNARY_NOT_r22 1620 +#define _UNARY_NOT_r33 1621 +#define _UNPACK_EX_r10 1622 +#define _UNPACK_SEQUENCE_r10 1623 +#define _UNPACK_SEQUENCE_LIST_r10 1624 +#define _UNPACK_SEQUENCE_TUPLE_r10 1625 +#define _UNPACK_SEQUENCE_TWO_TUPLE_r12 1626 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r03 1627 +#define _UNPACK_SEQUENCE_UNIQUE_THREE_TUPLE_r13 1628 +#define _UNPACK_SEQUENCE_UNIQUE_TUPLE_r10 1629 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r02 1630 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r12 1631 +#define _UNPACK_SEQUENCE_UNIQUE_TWO_TUPLE_r23 1632 +#define _WITH_EXCEPT_START_r33 1633 +#define _YIELD_VALUE_r11 1634 +#define MAX_UOP_REGS_ID 1634 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index cd1e95ffb2b141..688e6b0112b554 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -262,6 +262,8 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_PUSH_TAGGED_ZERO] = 0, [_GET_ITER_TRAD] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_FOR_ITER_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_GUARD_TYPE_ITER] = HAS_EXIT_FLAG, + [_ITER_NEXT_INLINE] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GUARD_NOS_ITER_VIRTUAL] = HAS_EXIT_FLAG, [_FOR_ITER_VIRTUAL_TIER_TWO] = HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_ITER_CHECK_LIST] = HAS_EXIT_FLAG, @@ -2485,6 +2487,24 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { { -1, -1, -1 }, }, }, + [_GUARD_TYPE_ITER] = { + .best = { 0, 1, 2, 3 }, + .entries = { + { 2, 0, _GUARD_TYPE_ITER_r02 }, + { 2, 1, _GUARD_TYPE_ITER_r12 }, + { 2, 2, _GUARD_TYPE_ITER_r22 }, + { 3, 3, _GUARD_TYPE_ITER_r33 }, + }, + }, + [_ITER_NEXT_INLINE] = { + .best = { 2, 2, 2, 2 }, + .entries = { + { -1, -1, -1 }, + { -1, -1, -1 }, + { 3, 2, _ITER_NEXT_INLINE_r23 }, + { -1, -1, -1 }, + }, + }, [_GUARD_NOS_ITER_VIRTUAL] = { .best = { 0, 1, 2, 3 }, .entries = { @@ -4398,6 +4418,11 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_PUSH_TAGGED_ZERO_r23] = _PUSH_TAGGED_ZERO, [_GET_ITER_TRAD_r12] = _GET_ITER_TRAD, [_FOR_ITER_TIER_TWO_r23] = _FOR_ITER_TIER_TWO, + [_GUARD_TYPE_ITER_r02] = _GUARD_TYPE_ITER, + [_GUARD_TYPE_ITER_r12] = _GUARD_TYPE_ITER, + [_GUARD_TYPE_ITER_r22] = _GUARD_TYPE_ITER, + [_GUARD_TYPE_ITER_r33] = _GUARD_TYPE_ITER, + [_ITER_NEXT_INLINE_r23] = _ITER_NEXT_INLINE, [_GUARD_NOS_ITER_VIRTUAL_r02] = _GUARD_NOS_ITER_VIRTUAL, [_GUARD_NOS_ITER_VIRTUAL_r12] = _GUARD_NOS_ITER_VIRTUAL, [_GUARD_NOS_ITER_VIRTUAL_r22] = _GUARD_NOS_ITER_VIRTUAL, @@ -5541,6 +5566,11 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_GUARD_TYPE_r11] = "_GUARD_TYPE_r11", [_GUARD_TYPE_r22] = "_GUARD_TYPE_r22", [_GUARD_TYPE_r33] = "_GUARD_TYPE_r33", + [_GUARD_TYPE_ITER] = "_GUARD_TYPE_ITER", + [_GUARD_TYPE_ITER_r02] = "_GUARD_TYPE_ITER_r02", + [_GUARD_TYPE_ITER_r12] = "_GUARD_TYPE_ITER_r12", + [_GUARD_TYPE_ITER_r22] = "_GUARD_TYPE_ITER_r22", + [_GUARD_TYPE_ITER_r33] = "_GUARD_TYPE_ITER_r33", [_GUARD_TYPE_VERSION] = "_GUARD_TYPE_VERSION", [_GUARD_TYPE_VERSION_r01] = "_GUARD_TYPE_VERSION_r01", [_GUARD_TYPE_VERSION_r11] = "_GUARD_TYPE_VERSION_r11", @@ -5597,6 +5627,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_ITER_CHECK_TUPLE_r12] = "_ITER_CHECK_TUPLE_r12", [_ITER_CHECK_TUPLE_r22] = "_ITER_CHECK_TUPLE_r22", [_ITER_CHECK_TUPLE_r33] = "_ITER_CHECK_TUPLE_r33", + [_ITER_NEXT_INLINE] = "_ITER_NEXT_INLINE", + [_ITER_NEXT_INLINE_r23] = "_ITER_NEXT_INLINE_r23", [_ITER_NEXT_LIST_TIER_TWO] = "_ITER_NEXT_LIST_TIER_TWO", [_ITER_NEXT_LIST_TIER_TWO_r23] = "_ITER_NEXT_LIST_TIER_TWO_r23", [_ITER_NEXT_RANGE] = "_ITER_NEXT_RANGE", @@ -6557,6 +6589,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _FOR_ITER_TIER_TWO: return 0; + case _GUARD_TYPE_ITER: + return 0; + case _ITER_NEXT_INLINE: + return 0; case _GUARD_NOS_ITER_VIRTUAL: return 0; case _FOR_ITER_VIRTUAL_TIER_TWO: diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index e371070d0b7c1c..6c2e33b27951ca 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -598,7 +598,7 @@ def testfunc(n, m): ex = get_first_executor(testfunc) self.assertIsNotNone(ex) uops = get_opnames(ex) - self.assertIn("_FOR_ITER_TIER_TWO", uops) + self.assertIn("_ITER_NEXT_INLINE", uops) @requires_specialization @@ -1461,7 +1461,132 @@ def testfunc(n): res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) self.assertEqual(res, TIER2_THRESHOLD * (TIER2_THRESHOLD - 1) // 2) self.assertIsNotNone(ex) - self.assertIn("_FOR_ITER_TIER_TWO", get_opnames(ex)) + self.assertIn("_ITER_NEXT_INLINE", get_opnames(ex)) + + def test_for_iter_direct_dict_items(self): + def testfunc(n): + d = {i: i * 2 for i in range(10)} + total = 0 + for _ in range(n): + for k, v in d.items(): + total += k + v + return total + + expected = 0 + d = {i: i * 2 for i in range(10)} + for _ in range(TIER2_THRESHOLD): + for k, v in d.items(): + expected += k + v + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_dict_keys(self): + def testfunc(n): + d = {i: i for i in range(10)} + total = 0 + for _ in range(n): + for k in d.keys(): + total += k + return total + + expected = TIER2_THRESHOLD * sum(range(10)) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_dict_values(self): + def testfunc(n): + d = {i: i * 3 for i in range(10)} + total = 0 + for _ in range(n): + for v in d.values(): + total += v + return total + + expected = TIER2_THRESHOLD * sum(i * 3 for i in range(10)) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_set(self): + def testfunc(n): + s = set(range(10)) + total = 0 + for _ in range(n): + for x in s: + total += x + return total + + expected = TIER2_THRESHOLD * sum(range(10)) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_reversed(self): + def testfunc(n): + lst = list(range(10)) + total = 0 + for _ in range(n): + for x in reversed(lst): + total += x + return total + + expected = TIER2_THRESHOLD * sum(range(10)) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_enumerate(self): + def testfunc(n): + lst = list(range(10)) + total = 0 + for _ in range(n): + for i, x in enumerate(lst): + total += i + x + return total + + expected = TIER2_THRESHOLD * sum(i + x for i, x in enumerate(range(10))) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) + + def test_for_iter_direct_zip(self): + def testfunc(n): + a = list(range(10)) + b = list(range(10, 20)) + total = 0 + for _ in range(n): + for x, y in zip(a, b): + total += x + y + return total + + expected = TIER2_THRESHOLD * sum(x + y for x, y in zip(range(10), range(10, 20))) + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, expected) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_ITER_NEXT_INLINE", uops) + self.assertNotIn("_FOR_ITER_TIER_TWO", uops) def test_modified_local_is_seen_by_optimized_code(self): l = sys._getframe().f_locals diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index 748309b54593a1..9915d7be7062d1 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -2181,8 +2181,8 @@ def test_family_member_needs_transform_only_when_shape_changes(self): output = self.generate_tables(input) self.assert_slot_map_lines( output, - "[OP_RAW] = {1, 1, {0}}", - "[OP_RAW_SPECIALIZED] = {1, 0, {0}}", + "[OP_RAW] = {1, 0, {0}}", + "[OP_RAW_SPECIALIZED] = {1, 1, {0}}", "[OP_TYPED] = {1, 0, {0}}", "[OP_TYPED_SPECIALIZED] = {1, 0, {0}}", ) @@ -2227,8 +2227,8 @@ def test_family_member_maps_non_positional_recorders_by_stack_shape(self): output = self.generate_tables(input) self.assert_slot_map_lines( output, - "[OP] = {1, 1, {0}}", - "[OP_SPECIALIZED] = {1, 0, {0}}", + "[OP] = {1, 0, {0}}", + "[OP_SPECIALIZED] = {1, 1, {0}}", ) def test_family_head_records_union_of_member_recorders(self): @@ -2277,12 +2277,12 @@ def test_family_detects_base_and_specialized_recording_difference(self): ), ["_RECORD_TOS_TYPE"], ) - self.assertIn("[OP] = {1, {_RECORD_TOS_TYPE_INDEX}}", output) - self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_TYPE_INDEX}}", output) + self.assertIn("[OP] = {1, {_RECORD_TOS_INDEX}}", output) + self.assertIn("[OP_SPECIALIZED] = {1, {_RECORD_TOS_INDEX}}", output) self.assert_slot_map_lines( output, - "[OP] = {1, 1, {0}}", - "[OP_SPECIALIZED] = {1, 0, {0}}", + "[OP] = {1, 0, {0}}", + "[OP_SPECIALIZED] = {1, 1, {0}}", ) def test_family_head_falls_back_for_missing_member_slots(self): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3f33b6be8679f9..daa989eb32ca1f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3756,7 +3756,7 @@ dummy_func( next = item; } - macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER; + macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _RECORD_NOS_TYPE + _FOR_ITER; op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) { _PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index); @@ -3771,6 +3771,31 @@ dummy_func( next = item; } + tier2 op(_GUARD_TYPE_ITER, (expected_type/4, iter, null_or_index -- iter, null_or_index)) { + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + EXIT_IF(Py_TYPE(iter_o) != (PyTypeObject *)expected_type); + } + + tier2 op(_ITER_NEXT_INLINE, (iternext_fn/4, iter, null_or_index -- iter, null_or_index, next)) { + assert(sizeof(iternextfunc) == sizeof(uintptr_t)); + volatile iternextfunc iternext_v = (iternextfunc)iternext_fn; + PyObject *item = iternext_v(PyStackRef_AsPyObjectBorrow(iter)); + if (item == NULL) { + if (_PyErr_Occurred(tstate)) { + if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + _PyEval_MonitorRaise(tstate, frame, frame->instr_ptr); + _PyErr_Clear(tstate); + } + else { + ERROR_NO_POP(); + } + } + EXIT_IF(true); + } + STAT_INC(FOR_ITER, hit); + next = PyStackRef_FromPyObjectSteal(item); + } + op(_GUARD_NOS_ITER_VIRTUAL, (iter, null_or_index -- iter, null_or_index)) { PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); EXIT_IF(Py_TYPE(iter_o)->_tp_iteritem == NULL); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index a82bec4c9fde36..29c901b2bae723 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -14072,6 +14072,152 @@ break; } + case _GUARD_TYPE_ITER_r02: { + CHECK_CURRENT_CACHED_VALUES(0); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + iter = stack_pointer[-2]; + PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64(); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) { + UOP_STAT_INC(uopcode, miss); + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = stack_pointer[-1]; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_ITER_r12: { + CHECK_CURRENT_CACHED_VALUES(1); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + iter = stack_pointer[-1]; + PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64(); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(1); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_0; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_ITER_r22: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + iter = _stack_item_0; + PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64(); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _GUARD_TYPE_ITER_r33: { + CHECK_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + _PyStackRef _stack_item_2 = _tos_cache2; + iter = _stack_item_1; + PyObject *expected_type = (PyObject *)CURRENT_OPERAND0_64(); + PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter); + if (Py_TYPE(iter_o) != (PyTypeObject *)expected_type) { + UOP_STAT_INC(uopcode, miss); + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + JUMP_TO_JUMP_TARGET(); + } + _tos_cache2 = _stack_item_2; + _tos_cache1 = iter; + _tos_cache0 = _stack_item_0; + SET_CURRENT_CACHED_VALUES(3); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + + case _ITER_NEXT_INLINE_r23: { + CHECK_CURRENT_CACHED_VALUES(2); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + _PyStackRef iter; + _PyStackRef next; + _PyStackRef _stack_item_0 = _tos_cache0; + _PyStackRef _stack_item_1 = _tos_cache1; + iter = _stack_item_0; + PyObject *iternext_fn = (PyObject *)CURRENT_OPERAND0_64(); + assert(sizeof(iternextfunc) == sizeof(uintptr_t)); + volatile iternextfunc iternext_v = (iternextfunc)iternext_fn; + stack_pointer[0] = iter; + stack_pointer[1] = _stack_item_1; + stack_pointer += 2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyObject *item = iternext_v(PyStackRef_AsPyObjectBorrow(iter)); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (item == NULL) { + if (_PyErr_Occurred(tstate)) { + if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + _PyFrame_SetStackPointer(frame, stack_pointer); + _PyEval_MonitorRaise(tstate, frame, frame->instr_ptr); + _PyErr_Clear(tstate); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + else { + SET_CURRENT_CACHED_VALUES(0); + JUMP_TO_ERROR(); + } + } + if (true) { + UOP_STAT_INC(uopcode, miss); + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(2); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + JUMP_TO_JUMP_TARGET(); + } + } + STAT_INC(FOR_ITER, hit); + next = PyStackRef_FromPyObjectSteal(item); + _tos_cache2 = next; + _tos_cache1 = _stack_item_1; + _tos_cache0 = iter; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); + break; + } + case _GUARD_NOS_ITER_VIRTUAL_r02: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); diff --git a/Python/optimizer.c b/Python/optimizer.c index 11658fca0da595..765bab9726088d 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -508,6 +508,7 @@ is_for_iter_test[MAX_UOP_ID + 1] = { [_GUARD_NOT_EXHAUSTED_LIST] = 1, [_GUARD_NOT_EXHAUSTED_TUPLE] = 1, [_FOR_ITER_TIER_TWO] = 1, + [_ITER_NEXT_INLINE] = 1, }; static const uint16_t diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 2dcfbb6d3418c0..f10c304fa02001 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1452,6 +1452,28 @@ dummy_func(void) { } } + op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) { + bool definite = true; + PyTypeObject *type = sym_get_type(iter); + if (type == NULL) { + type = sym_get_probable_type(iter); + definite = false; + } + if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL) { + PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); + _Py_BloomFilter_Add(dependencies, type); + if (!definite) { + sym_set_type(iter, type); + assert((this_instr - 1)->opcode == _RECORD_NOS_TYPE); + int32_t orig_target = (this_instr - 1)->target; + ADD_OP(_GUARD_TYPE_ITER, 0, (uintptr_t)type); + uop_buffer_last(&ctx->out_buffer)->target = orig_target; + } + ADD_OP(_ITER_NEXT_INLINE, 0, (uintptr_t)type->tp_iternext); + } + next = sym_new_not_null(ctx); + } + op(_GUARD_ITERATOR, (iterable -- iterable)) { bool definite = true; PyTypeObject *tp = sym_get_type(iterable); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 0942089760f639..0cad3524850df4 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3640,6 +3640,40 @@ /* _FOR_ITER is not a viable micro-op for tier 2 */ case _FOR_ITER_TIER_TWO: { + JitOptRef iter; + JitOptRef next; + iter = stack_pointer[-2]; + bool definite = true; + PyTypeObject *type = sym_get_type(iter); + if (type == NULL) { + type = sym_get_probable_type(iter); + definite = false; + } + if (type != NULL && type != &PyGen_Type && type->tp_iternext != NULL) { + PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type); + _Py_BloomFilter_Add(dependencies, type); + if (!definite) { + sym_set_type(iter, type); + assert((this_instr - 1)->opcode == _RECORD_NOS_TYPE); + int32_t orig_target = (this_instr - 1)->target; + ADD_OP(_GUARD_TYPE_ITER, 0, (uintptr_t)type); + uop_buffer_last(&ctx->out_buffer)->target = orig_target; + } + ADD_OP(_ITER_NEXT_INLINE, 0, (uintptr_t)type->tp_iternext); + } + next = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(1); + stack_pointer[0] = next; + stack_pointer += 1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + break; + } + + case _GUARD_TYPE_ITER: { + break; + } + + case _ITER_NEXT_INLINE: { JitOptRef next; next = sym_new_not_null(ctx); CHECK_STACK_BOUNDS(1); diff --git a/Python/record_functions.c.h b/Python/record_functions.c.h index 13996b30b9c03c..ce5d25b004ab3c 100644 --- a/Python/record_functions.c.h +++ b/Python/record_functions.c.h @@ -103,10 +103,9 @@ void _PyOpcode_RecordFunction_CODE(_PyInterpreterFrame *frame, _PyStackRef *stac #define _RECORD_NOS_TYPE_INDEX 3 #define _RECORD_3OS_GEN_FUNC_INDEX 4 #define _RECORD_TOS_INDEX 5 -#define _RECORD_NOS_GEN_FUNC_INDEX 6 -#define _RECORD_CALLABLE_INDEX 7 -#define _RECORD_CALLABLE_KW_INDEX 8 -#define _RECORD_4OS_INDEX 9 +#define _RECORD_CALLABLE_INDEX 6 +#define _RECORD_CALLABLE_KW_INDEX 7 +#define _RECORD_4OS_INDEX 8 const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = { [TO_BOOL_BOOL] = {1, {_RECORD_TOS_TYPE_INDEX}}, @@ -156,12 +155,12 @@ const _PyOpcodeRecordEntry _PyOpcode_RecordEntries[256] = { [GET_ITER] = {1, {_RECORD_TOS_TYPE_INDEX}}, [GET_ITER_SELF] = {1, {_RECORD_TOS_TYPE_INDEX}}, [GET_ITER_VIRTUAL] = {1, {_RECORD_TOS_TYPE_INDEX}}, - [FOR_ITER] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, - [FOR_ITER_VIRTUAL] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, - [FOR_ITER_LIST] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, - [FOR_ITER_TUPLE] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, - [FOR_ITER_RANGE] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, - [FOR_ITER_GEN] = {1, {_RECORD_NOS_GEN_FUNC_INDEX}}, + [FOR_ITER] = {1, {_RECORD_NOS_INDEX}}, + [FOR_ITER_VIRTUAL] = {1, {_RECORD_NOS_INDEX}}, + [FOR_ITER_LIST] = {1, {_RECORD_NOS_INDEX}}, + [FOR_ITER_TUPLE] = {1, {_RECORD_NOS_INDEX}}, + [FOR_ITER_RANGE] = {1, {_RECORD_NOS_INDEX}}, + [FOR_ITER_GEN] = {1, {_RECORD_NOS_INDEX}}, [LOAD_SPECIAL] = {1, {_RECORD_TOS_TYPE_INDEX}}, [LOAD_ATTR_METHOD_WITH_VALUES] = {1, {_RECORD_TOS_INDEX}}, [LOAD_ATTR_METHOD_NO_DICT] = {1, {_RECORD_TOS_INDEX}}, @@ -219,7 +218,8 @@ const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = { [GET_ITER] = {1, 0, {0}}, [GET_ITER_SELF] = {1, 0, {0}}, [GET_ITER_VIRTUAL] = {1, 0, {0}}, - [FOR_ITER_GEN] = {1, 0, {0}}, + [FOR_ITER] = {1, 1, {0}}, + [FOR_ITER_GEN] = {1, 1, {0}}, [LOAD_SPECIAL] = {1, 0, {0}}, [LOAD_ATTR_METHOD_WITH_VALUES] = {1, 1, {0}}, [LOAD_ATTR_METHOD_NO_DICT] = {1, 1, {0}}, @@ -245,14 +245,13 @@ const _PyOpcodeRecordSlotMap _PyOpcode_RecordSlotMaps[256] = { [BINARY_OP] = {2, 2, {1, 0}}, }; -const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[10] = { +const _Py_RecordFuncPtr _PyOpcode_RecordFunctions[9] = { [0] = NULL, [_RECORD_TOS_TYPE_INDEX] = _PyOpcode_RecordFunction_TOS_TYPE, [_RECORD_NOS_INDEX] = _PyOpcode_RecordFunction_NOS, [_RECORD_NOS_TYPE_INDEX] = _PyOpcode_RecordFunction_NOS_TYPE, [_RECORD_3OS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_3OS_GEN_FUNC, [_RECORD_TOS_INDEX] = _PyOpcode_RecordFunction_TOS, - [_RECORD_NOS_GEN_FUNC_INDEX] = _PyOpcode_RecordFunction_NOS_GEN_FUNC, [_RECORD_CALLABLE_INDEX] = _PyOpcode_RecordFunction_CALLABLE, [_RECORD_CALLABLE_KW_INDEX] = _PyOpcode_RecordFunction_CALLABLE_KW, [_RECORD_4OS_INDEX] = _PyOpcode_RecordFunction_4OS, diff --git a/Tools/cases_generator/record_function_generator.py b/Tools/cases_generator/record_function_generator.py index 6f518ffdcf2ac2..118ffa6c89caaa 100644 --- a/Tools/cases_generator/record_function_generator.py +++ b/Tools/cases_generator/record_function_generator.py @@ -86,33 +86,31 @@ def get_family_record_names( record_slot_keys: dict[str, str], ) -> list[str]: member_records = [instruction_records[m.name] for m in family_members] - all_member_names = {n for names in member_records for n in names} + head_records = instruction_records[family_head.name] records: list[str] = [] slot_index: dict[str, int] = {} def add(name: str) -> None: kind = record_slot_keys[name] - # Prefer the raw recorder if any member uses it; otherwise the given form. - raw = f"_RECORD_{kind}" - source = raw if raw in all_member_names else name existing = slot_index.get(kind) if existing is None: slot_index[kind] = len(records) - records.append(source) - elif records[existing] != source: - raise ValueError( - f"Family {family_head.name} has incompatible recorders for " - f"slot {kind}: {records[existing]} and {source}" - ) + records.append(name) + elif records[existing] != name: + raw = f"_RECORD_{kind}" + if raw not in record_slot_keys: + raise ValueError( + f"Family {family_head.name} has incompatible recorders for " + f"slot {kind}: {records[existing]} and {name}, " + f"and no raw recorder {raw} exists to use as a base." + ) + records[existing] = raw for names in member_records: for name in names: add(name) - # Family head supplies any slots no member exercises. - for name in instruction_records[family_head.name]: - if record_slot_keys[name] not in slot_index: - slot_index[record_slot_keys[name]] = len(records) - records.append(name) + for name in head_records: + add(name) return records From 10f950c9bb0ff4583f361a42aaed562b330e1dba Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 4 May 2026 17:45:08 +0100 Subject: [PATCH 18/18] gh-148690: Build Windows freethreaded binaries into separate directory and include python3t.dll on GIL-enabled (GH-149218) Co-authored-by: Petr Viktorin --- Include/pyabi.h | 2 + Lib/test/test_cext/__init__.py | 5 + Lib/test/test_cext/setup.py | 22 ++-- Lib/test/test_cppext/__init__.py | 4 + Lib/test/test_cppext/setup.py | 22 ++-- Lib/venv/__init__.py | 3 + ...-05-01-12-01-54.gh-issue-148690.oTtYk-.rst | 4 + ...-05-01-12-03-39.gh-issue-148690.TMV8dU.rst | 3 + PC/layout/main.py | 12 +- PC/pyconfig.h | 4 +- PCbuild/_remote_debugging.vcxproj | 4 + PCbuild/_testcapi.vcxproj | 4 + PCbuild/_testlimitedcapi.vcxproj | 4 + PCbuild/pcbuild.proj | 2 + PCbuild/pcbuild.sln | 69 +++++++++++ PCbuild/pyproject.props | 10 +- PCbuild/python.props | 30 ++++- PCbuild/python3dll.vcxproj | 2 +- PCbuild/python3tdll.vcxproj | 110 ++++++++++++++++++ PCbuild/python3tdll.vcxproj.filters | 23 ++++ PCbuild/pythoncore.vcxproj | 5 +- PCbuild/readme.txt | 4 + PCbuild/rt.bat | 8 +- PCbuild/xxlimited.vcxproj | 3 + PCbuild/xxlimited_35.vcxproj | 3 + PCbuild/zlib-ng.vcxproj | 6 +- Python/dynload_win.c | 80 ++++++++++++- Tools/msi/common.wxs | 6 + Tools/msi/core/core_files.wxs | 6 + Tools/msi/freethreaded/freethreaded_files.wxs | 64 +++++----- Tools/msi/msi.props | 34 ++++++ Tools/peg_generator/pegen/build.py | 8 +- 32 files changed, 488 insertions(+), 78 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2026-05-01-12-01-54.gh-issue-148690.oTtYk-.rst create mode 100644 Misc/NEWS.d/next/Windows/2026-05-01-12-03-39.gh-issue-148690.TMV8dU.rst create mode 100644 PCbuild/python3tdll.vcxproj create mode 100644 PCbuild/python3tdll.vcxproj.filters diff --git a/Include/pyabi.h b/Include/pyabi.h index 8c4ae281a43faf..21a6ab0c1ee6ea 100644 --- a/Include/pyabi.h +++ b/Include/pyabi.h @@ -55,6 +55,8 @@ * * (Don't use Py_TARGET_ABI3T directly. It's currently only used to set these * 2 macros, and defined for users' convenience.) + * + * This logic is currently partially duplicated in PC/pyconfig.h. */ #if defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED) \ && !defined(Py_TARGET_ABI3T) diff --git a/Lib/test/test_cext/__init__.py b/Lib/test/test_cext/__init__.py index 1958c44e2b64ef..4cc5f843dd388d 100644 --- a/Lib/test/test_cext/__init__.py +++ b/Lib/test/test_cext/__init__.py @@ -8,6 +8,8 @@ import shlex import shutil import subprocess +import sysconfig +import sys import unittest from test import support @@ -62,6 +64,9 @@ def run_cmd(operation, cmd): env['CPYTHON_TEST_LIMITED'] = '1' if abi3t: env['CPYTHON_TEST_ABI3T'] = '1' + if support.MS_WINDOWS and sysconfig.is_python_build(): + env['CPYTHON_EXTRA_INCDIRS'] = os.path.split(sysconfig.get_config_h_filename())[0] + env['CPYTHON_EXTRA_LIBDIRS'] = os.path.split(sys.executable)[0] env['CPYTHON_TEST_EXT_NAME'] = extension_name env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API)) if support.verbose: diff --git a/Lib/test/test_cext/setup.py b/Lib/test/test_cext/setup.py index 25fe50df603883..1eca44bdf823dc 100644 --- a/Lib/test/test_cext/setup.py +++ b/Lib/test/test_cext/setup.py @@ -1,7 +1,6 @@ # gh-91321: Build a basic C test extension to check that the Python C API is # compatible with C and does not emit C compiler warnings. import os -import platform import shlex import sys import sysconfig @@ -66,6 +65,8 @@ def main(): limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", "")) abi3t = bool(os.environ.get("CPYTHON_TEST_ABI3T", "")) internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0"))) + incdirs = os.environ.get("CPYTHON_EXTRA_INCDIRS", "") + libdirs = os.environ.get("CPYTHON_EXTRA_LIBDIRS", "") sources = [SOURCE] @@ -106,19 +107,16 @@ def main(): if internal: cflags.append('-DTEST_INTERNAL_C_API=1') - # On Windows, add PCbuild\amd64\ to include and library directories + # Add additional include and library directories, typically for in-tree + # testing where not all directories are inferred include_dirs = [] library_dirs = [] - if support.MS_WINDOWS: - srcdir = sysconfig.get_config_var('srcdir') - machine = platform.uname().machine - pcbuild = os.path.join(srcdir, 'PCbuild', machine) - if os.path.exists(pcbuild): - # pyconfig.h is generated in PCbuild\amd64\ - include_dirs.append(pcbuild) - # python313.lib is generated in PCbuild\amd64\ - library_dirs.append(pcbuild) - print(f"Add PCbuild directory: {pcbuild}") + if incdirs: + print("Add incdirs:", incdirs) + include_dirs.extend(incdirs.split(os.pathsep)) + if libdirs: + print("Add libdirs:", libdirs) + library_dirs.extend(libdirs.split(os.pathsep)) # Display information to help debugging for env_name in ('CC', 'CFLAGS', 'CPPFLAGS'): diff --git a/Lib/test/test_cppext/__init__.py b/Lib/test/test_cppext/__init__.py index 5b4c97c181bb6a..967feee6693c03 100644 --- a/Lib/test/test_cppext/__init__.py +++ b/Lib/test/test_cppext/__init__.py @@ -6,6 +6,7 @@ import shutil import subprocess import sys +import sysconfig import unittest from test import support @@ -50,6 +51,9 @@ def run_cmd(operation, cmd): env['CPYTHON_TEST_CPP_STD'] = std if limited: env['CPYTHON_TEST_LIMITED'] = '1' + if support.MS_WINDOWS and sysconfig.is_python_build(): + env['CPYTHON_EXTRA_INCDIRS'] = os.path.split(sysconfig.get_config_h_filename())[0] + env['CPYTHON_EXTRA_LIBDIRS'] = os.path.split(sys.executable)[0] env['CPYTHON_TEST_EXT_NAME'] = extension_name env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API)) if extra_cflags: diff --git a/Lib/test/test_cppext/setup.py b/Lib/test/test_cppext/setup.py index 14aeafefcaa8f7..5d004ca6e3ad78 100644 --- a/Lib/test/test_cppext/setup.py +++ b/Lib/test/test_cppext/setup.py @@ -1,7 +1,6 @@ # gh-91321: Build a basic C++ test extension to check that the Python C API is # compatible with C++ and does not emit C++ compiler warnings. import os -import platform import shlex import sys import sysconfig @@ -48,6 +47,8 @@ def main(): module_name = os.environ["CPYTHON_TEST_EXT_NAME"] limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", "")) internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0"))) + incdirs = os.environ.get("CPYTHON_EXTRA_INCDIRS", "") + libdirs = os.environ.get("CPYTHON_EXTRA_LIBDIRS", "") cppflags = list(CPPFLAGS) cppflags.append(f'-DMODULE_NAME={module_name}') @@ -90,19 +91,16 @@ def main(): if extra_cflags: cppflags.extend(shlex.split(extra_cflags)) - # On Windows, add PCbuild\amd64\ to include and library directories + # Add additional include and library directories, typically for in-tree + # testing where not all directories are inferred include_dirs = [] library_dirs = [] - if support.MS_WINDOWS: - srcdir = sysconfig.get_config_var('srcdir') - machine = platform.uname().machine - pcbuild = os.path.join(srcdir, 'PCbuild', machine) - if os.path.exists(pcbuild): - # pyconfig.h is generated in PCbuild\amd64\ - include_dirs.append(pcbuild) - # python313.lib is generated in PCbuild\amd64\ - library_dirs.append(pcbuild) - print(f"Add PCbuild directory: {pcbuild}") + if incdirs: + print("Add incdirs:", incdirs) + include_dirs.extend(incdirs.split(os.pathsep)) + if libdirs: + print("Add libdirs:", libdirs) + library_dirs.extend(libdirs.split(os.pathsep)) # Display information to help debugging for env_name in ('CC', 'CXX', 'CFLAGS', 'CPPFLAGS', 'CXXFLAGS'): diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py index 21f82125f5a7c4..002f4ebc988a3b 100644 --- a/Lib/venv/__init__.py +++ b/Lib/venv/__init__.py @@ -358,6 +358,9 @@ def setup_python(self, context): exe_t = f'3.{sys.version_info[1]}t' python_exe = os.path.join(dirname, f'python{exe_t}{exe_d}.exe') pythonw_exe = os.path.join(dirname, f'pythonw{exe_t}{exe_d}.exe') + if not os.path.isfile(python_exe): + python_exe = os.path.join(dirname, f'python{exe_d}.exe') + pythonw_exe = os.path.join(dirname, f'pythonw{exe_d}.exe') link_sources = { 'python.exe': python_exe, f'python{exe_d}.exe': python_exe, diff --git a/Misc/NEWS.d/next/Build/2026-05-01-12-01-54.gh-issue-148690.oTtYk-.rst b/Misc/NEWS.d/next/Build/2026-05-01-12-01-54.gh-issue-148690.oTtYk-.rst new file mode 100644 index 00000000000000..6845bad2b278de --- /dev/null +++ b/Misc/NEWS.d/next/Build/2026-05-01-12-01-54.gh-issue-148690.oTtYk-.rst @@ -0,0 +1,4 @@ +Windows free-threaded builds now output to a different default path with +default filenames, for example, ``PCbuild/amd64t/python.exe`` rather than +``PCbuild/amd64/python3.15t.exe``. The ``PC/layout`` script has been updated +to ensure compatibility of generated layouts. diff --git a/Misc/NEWS.d/next/Windows/2026-05-01-12-03-39.gh-issue-148690.TMV8dU.rst b/Misc/NEWS.d/next/Windows/2026-05-01-12-03-39.gh-issue-148690.TMV8dU.rst new file mode 100644 index 00000000000000..1fa30f10e0e3dc --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2026-05-01-12-03-39.gh-issue-148690.TMV8dU.rst @@ -0,0 +1,3 @@ +Non-freethreaded builds on Windows now support extensions linked to +``python3t.dll``, and will include a copy of that library in normal installs +that references the non-freethreaded runtime. diff --git a/PC/layout/main.py b/PC/layout/main.py index 8543e7c56e1c41..3566b8bd873874 100644 --- a/PC/layout/main.py +++ b/PC/layout/main.py @@ -127,7 +127,10 @@ def get_tcltk_lib(ns): def get_layout(ns): def in_build(f, dest="", new_name=None, no_lib=False): n, _, x = f.rpartition(".") - n = new_name or n + if new_name and new_name.endswith(f".{x}"): + n = new_name.rpartition(".")[0] + else: + n = new_name or n src = ns.build / f if ns.debug and src not in REQUIRED_DLLS: if not "_d." in src.name: @@ -161,11 +164,12 @@ def in_build(f, dest="", new_name=None, no_lib=False): source = "python_uwp.exe" sourcew = "pythonw_uwp.exe" elif ns.include_freethreaded: - source = "python{}t.exe".format(VER_DOT) - sourcew = "pythonw{}t.exe".format(VER_DOT) if not ns.include_alias: alias = [] aliasw = [] + if (VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4) < (3, 15, 0, 0xB0): + source = "python{}t.exe".format(VER_DOT) + sourcew = "pythonw{}t.exe".format(VER_DOT) alias.extend([ "python{}t".format(VER_DOT), "python{}t".format(VER_MAJOR) if ns.include_alias3 else None, @@ -196,6 +200,8 @@ def in_build(f, dest="", new_name=None, no_lib=False): yield from in_build(FREETHREADED_PYTHON_STABLE_DLL_NAME) else: yield from in_build(PYTHON_STABLE_DLL_NAME) + if (VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4) >= (3, 15, 0, 0xB0): + yield from in_build(FREETHREADED_PYTHON_STABLE_DLL_NAME) found_any = False for dest, src in rglob(ns.build, "vcruntime*.dll"): diff --git a/PC/pyconfig.h b/PC/pyconfig.h index a126fca6f5aafb..72a475777b7ad0 100644 --- a/PC/pyconfig.h +++ b/PC/pyconfig.h @@ -331,7 +331,7 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # if defined(Py_GIL_DISABLED) # if defined(Py_DEBUG) # pragma comment(lib,"python315t_d.lib") -# elif defined(Py_LIMITED_API) +# elif defined(Py_LIMITED_API) || defined(Py_TARGET_ABI3T) # pragma comment(lib,"python3t.lib") # else # pragma comment(lib,"python315t.lib") @@ -339,6 +339,8 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # else /* Py_GIL_DISABLED */ # if defined(Py_DEBUG) # pragma comment(lib,"python315_d.lib") +# elif defined(Py_TARGET_ABI3T) +# pragma comment(lib,"python3t.lib") # elif defined(Py_LIMITED_API) # pragma comment(lib,"python3.lib") # else diff --git a/PCbuild/_remote_debugging.vcxproj b/PCbuild/_remote_debugging.vcxproj index 3a9b4033a697ad..41aadbd13d0995 100644 --- a/PCbuild/_remote_debugging.vcxproj +++ b/PCbuild/_remote_debugging.vcxproj @@ -128,6 +128,10 @@ {885d4898-d08d-4091-9c40-c700cfe3fc5a} false + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + false + diff --git a/PCbuild/_testcapi.vcxproj b/PCbuild/_testcapi.vcxproj index 68707a54ff6b87..62312acf248b91 100644 --- a/PCbuild/_testcapi.vcxproj +++ b/PCbuild/_testcapi.vcxproj @@ -146,6 +146,10 @@ {885d4898-d08d-4091-9c40-c700cfe3fc5a} false + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + false + diff --git a/PCbuild/_testlimitedcapi.vcxproj b/PCbuild/_testlimitedcapi.vcxproj index 935467dfcb3283..3d70517fbe31e8 100644 --- a/PCbuild/_testlimitedcapi.vcxproj +++ b/PCbuild/_testlimitedcapi.vcxproj @@ -129,6 +129,10 @@ {885d4898-d08d-4091-9c40-c700cfe3fc5a} false + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + false + diff --git a/PCbuild/pcbuild.proj b/PCbuild/pcbuild.proj index 7a5327bf016cea..bb7d8042176d8f 100644 --- a/PCbuild/pcbuild.proj +++ b/PCbuild/pcbuild.proj @@ -61,6 +61,8 @@ + + diff --git a/PCbuild/pcbuild.sln b/PCbuild/pcbuild.sln index 7296ea75301157..09a989d38648df 100644 --- a/PCbuild/pcbuild.sln +++ b/PCbuild/pcbuild.sln @@ -33,6 +33,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python", "python.vcxproj", {78D80A15-BD8C-44E2-B49E-1F05B0A0A687} = {78D80A15-BD8C-44E2-B49E-1F05B0A0A687} {86937F53-C189-40EF-8CE8-8759D8E7D480} = {86937F53-C189-40EF-8CE8-8759D8E7D480} {885D4898-D08D-4091-9C40-C700CFE3FC5A} = {885D4898-D08D-4091-9C40-C700CFE3FC5A} + {947BB5F5-6025-4A4F-8182-1B175469F8D2} = {947BB5F5-6025-4A4F-8182-1B175469F8D2} {900342D7-516A-4469-B1AD-59A66E49A25F} = {900342D7-516A-4469-B1AD-59A66E49A25F} {9E48B300-37D1-11DD-8C41-005056C00008} = {9E48B300-37D1-11DD-8C41-005056C00008} {9EC7190A-249F-4180-A900-548FDCF3055F} = {9EC7190A-249F-4180-A900-548FDCF3055F} @@ -104,6 +105,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_multiprocessing", "_multip EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python3dll", "python3dll.vcxproj", "{885D4898-D08D-4091-9C40-C700CFE3FC5A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python3tdll", "python3tdll.vcxproj", "{947BB5F5-6025-4A4F-8182-1B175469F8D2}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxlimited", "xxlimited.vcxproj", "{F749B822-B489-4CA5-A3AD-CE078F5F338A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testbuffer", "_testbuffer.vcxproj", "{A2697BD3-28C1-4AEC-9106-8B748639FD16}" @@ -168,6 +171,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_remote_debugging", "_remot EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_zstd", "_zstd.vcxproj", "{07029B86-F3E9-443E-86FB-78AA6D47FED1}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxlimited_35", "xxlimited_35.vcxproj", "{FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM = Debug|ARM @@ -984,6 +989,38 @@ Global {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64 {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.Build.0 = Release|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|ARM.ActiveCfg = Debug|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|ARM.Build.0 = Debug|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|ARM64.Build.0 = Debug|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|Win32.ActiveCfg = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|Win32.Build.0 = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|x64.ActiveCfg = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Debug|x64.Build.0 = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|ARM.Build.0 = PGInstrument|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|Win32.ActiveCfg = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|Win32.Build.0 = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|x64.ActiveCfg = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGInstrument|x64.Build.0 = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|ARM.Build.0 = PGUpdate|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|Win32.ActiveCfg = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|Win32.Build.0 = Debug|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|x64.ActiveCfg = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.PGUpdate|x64.Build.0 = Debug|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|ARM.ActiveCfg = Release|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|ARM.Build.0 = Release|ARM + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|ARM64.ActiveCfg = Release|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|ARM64.Build.0 = Release|ARM64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|Win32.ActiveCfg = Release|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|Win32.Build.0 = Release|Win32 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|x64.ActiveCfg = Release|x64 + {947BB5F5-6025-4A4F-8182-1B175469F8D2}.Release|x64.Build.0 = Release|x64 {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|ARM.ActiveCfg = Debug|ARM {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|Win32.ActiveCfg = Release|Win32 @@ -1785,6 +1822,38 @@ Global {07029B86-F3E9-443E-86FB-78AA6D47FED1}.Release|Win32.Build.0 = Release|Win32 {07029B86-F3E9-443E-86FB-78AA6D47FED1}.Release|x64.ActiveCfg = Release|x64 {07029B86-F3E9-443E-86FB-78AA6D47FED1}.Release|x64.Build.0 = Release|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|ARM.ActiveCfg = Debug|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|ARM.Build.0 = Debug|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|ARM64.Build.0 = Debug|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|Win32.ActiveCfg = Debug|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|Win32.Build.0 = Debug|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|x64.ActiveCfg = Debug|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Debug|x64.Build.0 = Debug|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|ARM.ActiveCfg = PGInstrument|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|ARM.Build.0 = PGInstrument|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|ARM64.ActiveCfg = PGInstrument|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|ARM64.Build.0 = PGInstrument|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|x64.ActiveCfg = PGInstrument|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGInstrument|x64.Build.0 = PGInstrument|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|ARM.ActiveCfg = PGUpdate|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|ARM.Build.0 = PGUpdate|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|ARM64.ActiveCfg = PGUpdate|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|ARM64.Build.0 = PGUpdate|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|x64.ActiveCfg = PGUpdate|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.PGUpdate|x64.Build.0 = PGUpdate|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|ARM.ActiveCfg = Release|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|ARM.Build.0 = Release|ARM + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|ARM64.ActiveCfg = Release|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|ARM64.Build.0 = Release|ARM64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|Win32.ActiveCfg = Release|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|Win32.Build.0 = Release|Win32 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|x64.ActiveCfg = Release|x64 + {FB868EA7-F93A-4D9B-BE78-CA4E9BA14FFF}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PCbuild/pyproject.props b/PCbuild/pyproject.props index f79608e1d58dbc..7435c53e3fdcf9 100644 --- a/PCbuild/pyproject.props +++ b/PCbuild/pyproject.props @@ -9,6 +9,7 @@ $(OutDir)\ $(MSBuildThisFileDirectory)obj\ $(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\$(ProjectName)\ + $(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)t_$(Configuration)\$(ProjectName)\ $(IntDir.Replace(`\\`, `\`)) $(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)_frozen\ $(Py_IntDir)\$(MajorVersionNumber)$(MinorVersionNumber)$(ArchName)_$(Configuration)\zlib-ng\ @@ -42,6 +43,10 @@ + <_DebugPreprocessorDefinition>NDEBUG; <_DebugPreprocessorDefinition Condition="$(Configuration) == 'Debug'">_DEBUG; <_PyStatsPreprocessorDefinition>PyStats; @@ -49,15 +54,14 @@ <_PlatformPreprocessorDefinition>_WIN32; <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64'">_WIN64; <_PlatformPreprocessorDefinition Condition="$(Platform) == 'x64' and $(PlatformToolset) != 'ClangCL'">_M_X64;$(_PlatformPreprocessorDefinition) - <_Py3NamePreprocessorDefinition>PY3_DLLNAME=L"$(Py3DllName)$(PyDebugExt)"; <_FreeThreadedPreprocessorDefinition Condition="$(DisableGil) == 'true'">Py_GIL_DISABLED=1; <_PymallocHugepagesPreprocessorDefinition Condition="$(UsePymallocHugepages) == 'true'">PYMALLOC_USE_HUGEPAGES=1; + <_PyUsingPgoPreprocessorDefinition Condition="'$(SupportPGO)' and ($(Configuration) == 'PGInstrument' or $(Configuration) == 'PGUpdate')">_Py_USING_PGO=1; $(PySourcePath)Include;$(PySourcePath)Include\internal;$(PySourcePath)Include\internal\mimalloc;$(PySourcePath)PC;%(AdditionalIncludeDirectories) - WIN32;$(_Py3NamePreprocessorDefinition)$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PyStatsPreprocessorDefinition)$(_PydPreprocessorDefinition)$(_FreeThreadedPreprocessorDefinition)$(_PymallocHugepagesPreprocessorDefinition)%(PreprocessorDefinitions) - _Py_USING_PGO=1;%(PreprocessorDefinitions) + WIN32;$(_PlatformPreprocessorDefinition)$(_DebugPreprocessorDefinition)$(_PyStatsPreprocessorDefinition)$(_PydPreprocessorDefinition)$(_FreeThreadedPreprocessorDefinition)$(_PymallocHugepagesPreprocessorDefinition)$(_PyUsingPgoPreprocessorDefinition)%(PreprocessorDefinitions) MaxSpeed true diff --git a/PCbuild/python.props b/PCbuild/python.props index f29f3d18de5f9d..f70321f887ef8c 100644 --- a/PCbuild/python.props +++ b/PCbuild/python.props @@ -43,7 +43,7 @@ $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)\..\)) $(PySourcePath)\ - + $(PySourcePath)PCbuild\win32\ $(Py_OutDir)\win32\ $(PySourcePath)PCbuild\amd64\ @@ -52,11 +52,34 @@ $(Py_OutDir)\arm32\ $(PySourcePath)PCbuild\arm64\ $(Py_OutDir)\arm64\ + $(PySourcePath)PCbuild\win32t\ + $(Py_OutDir)\win32t\ + $(PySourcePath)PCbuild\amd64t\ + $(Py_OutDir)\amd64t\ + $(PySourcePath)PCbuild\arm32t\ + $(Py_OutDir)\arm32t\ + $(PySourcePath)PCbuild\arm64t\ + $(Py_OutDir)\arm64t\ + + + $(BuildPath32) $(BuildPath64) $(BuildPathArm32) $(BuildPathArm64) $(PySourcePath)PCbuild\$(ArchName)\ + + + + + $(BuildPath32t) + $(BuildPath64t) + $(BuildPathArm32t) + $(BuildPathArm64t) + $(PySourcePath)PCbuild\$(ArchName)t\ + + + $(BuildPath)\ $(BuildPath)instrumented\ @@ -232,18 +255,17 @@ $([msbuild]::Add($(Field3Value), 9000)) - python$(MajorVersionNumber).$(MinorVersionNumber)t python $(BuildPath)$(PyExeName)$(PyDebugExt).exe - pythonw$(MajorVersionNumber).$(MinorVersionNumber)t pythonw python$(MajorVersionNumber)$(MinorVersionNumber)t$(PyDebugExt) python$(MajorVersionNumber)$(MinorVersionNumber)$(PyDebugExt) + - python3t python3 + python3t .cp$(MajorVersionNumber)$(MinorVersionNumber)-win32 diff --git a/PCbuild/python3dll.vcxproj b/PCbuild/python3dll.vcxproj index 235ea1cf9d33fb..3d8ac1b23532c1 100644 --- a/PCbuild/python3dll.vcxproj +++ b/PCbuild/python3dll.vcxproj @@ -75,7 +75,7 @@ - $(Py3DllName) + python3 DynamicLibrary diff --git a/PCbuild/python3tdll.vcxproj b/PCbuild/python3tdll.vcxproj new file mode 100644 index 00000000000000..796712cca3146c --- /dev/null +++ b/PCbuild/python3tdll.vcxproj @@ -0,0 +1,110 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + PGInstrument + ARM + + + PGInstrument + ARM64 + + + PGInstrument + Win32 + + + PGInstrument + x64 + + + PGUpdate + ARM + + + PGUpdate + ARM64 + + + PGUpdate + Win32 + + + PGUpdate + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + python3tdll + Win32Proj + false + + + + + python3t + DynamicLibrary + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + PYTHON_DLL_NAME="$(PyDllName)";%(PreprocessorDefinitions) + false + + + true + + + + + + + + + + + + diff --git a/PCbuild/python3tdll.vcxproj.filters b/PCbuild/python3tdll.vcxproj.filters new file mode 100644 index 00000000000000..37510e3c7398f2 --- /dev/null +++ b/PCbuild/python3tdll.vcxproj.filters @@ -0,0 +1,23 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + + + Resource Files + + + diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index fae4a90b4536fc..f820c3dd64f58c 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -618,7 +618,10 @@ - + + PY3_DLLNAME=L"$(Py3DllName)";%(PreprocessorDefinitions) + ABI3T_DLLNAME=L"$(Abi3tDllName)";%(PreprocessorDefinitions) + diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index b98a956034c537..c291b7f86325f2 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -160,6 +160,10 @@ pyshellext pyshellext.dll, the shell extension deployed with the launcher python3dll python3.dll, the PEP 384 Stable ABI dll + (not installed on free-threaded builds) +python3tdll + python3t.dll, the PEP 803 free-threading Stable ABI dll + (built from the same source as python3.dll) xxlimited builds an example module that makes use of the PEP 384 Stable ABI, see Modules\xxlimited.c diff --git a/PCbuild/rt.bat b/PCbuild/rt.bat index f1e0607393405b..d5c9a24f292327 100644 --- a/PCbuild/rt.bat +++ b/PCbuild/rt.bat @@ -32,6 +32,7 @@ setlocal set pcbuild=%~dp0 set pyname=python set suffix= +set suffix1= set qmode= set dashO= set regrtestargs=--fast-ci @@ -41,8 +42,7 @@ set exe= if "%~1"=="-O" (set dashO=-O) & shift & goto CheckOpts if "%~1"=="-q" (set qmode=yes) & shift & goto CheckOpts if "%~1"=="-d" (set suffix=_d) & shift & goto CheckOpts -rem HACK: Need some way to infer the version number in this script -if "%~1"=="--disable-gil" (set pyname=python3.15t) & shift & goto CheckOpts +if "%~1"=="--disable-gil" (set suffix1=t) & shift & goto CheckOpts if "%~1"=="-win32" (set prefix=%pcbuild%win32) & shift & goto CheckOpts if "%~1"=="-x64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts if "%~1"=="-amd64" (set prefix=%pcbuild%amd64) & shift & goto CheckOpts @@ -52,7 +52,7 @@ if "%~1"=="-p" (call :SetPlatform %~2) & shift & shift & goto CheckOpts if NOT "%~1"=="" (set regrtestargs=%regrtestargs% %~1) & shift & goto CheckOpts if not defined prefix set prefix=%pcbuild%amd64 -set exe=%prefix%\%pyname%%suffix%.exe +set exe=%prefix%%suffix1%\%pyname%%suffix%.exe set cmd="%exe%" %dashO% -m test %regrtestargs% if defined qmode goto Qmode @@ -60,7 +60,7 @@ echo Deleting .pyc files ... "%exe%" "%pcbuild%rmpyc.py" echo Cleaning _pth files ... -if exist %prefix%\*._pth del %prefix%\*._pth +if exist %prefix%%suffix1%\*._pth del %prefix%%suffix1%\*._pth echo on %cmd% diff --git a/PCbuild/xxlimited.vcxproj b/PCbuild/xxlimited.vcxproj index 093e6920c0b76c..f0c3616600148f 100644 --- a/PCbuild/xxlimited.vcxproj +++ b/PCbuild/xxlimited.vcxproj @@ -104,6 +104,9 @@ {885d4898-d08d-4091-9c40-c700cfe3fc5a} + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + diff --git a/PCbuild/xxlimited_35.vcxproj b/PCbuild/xxlimited_35.vcxproj index 3f4d4463f24af0..bfaf4e253664d4 100644 --- a/PCbuild/xxlimited_35.vcxproj +++ b/PCbuild/xxlimited_35.vcxproj @@ -104,6 +104,9 @@ {885d4898-d08d-4091-9c40-c700cfe3fc5a} + + {947BB5F5-6025-4A4F-8182-1B175469F8D2} + diff --git a/PCbuild/zlib-ng.vcxproj b/PCbuild/zlib-ng.vcxproj index de1698ae718473..ffe8e70f2dbbc7 100644 --- a/PCbuild/zlib-ng.vcxproj +++ b/PCbuild/zlib-ng.vcxproj @@ -219,13 +219,15 @@ $([System.IO.File]::ReadAllText('$(zlibNgDir)\zlib.h.in').Replace('@ZLIB_SYMBOL_PREFIX@', '')) - + + $([System.IO.File]::ReadAllText('$(zlibNgDir)\zlib-ng.h.in').Replace('@ZLIB_SYMBOL_PREFIX@', '')) - + + prefix); if (config->prefix) { wcscpy_s(py3path, MAXPATHLEN, config->prefix); - if (py3path[0] && _Py_add_relfile(py3path, L"DLLs\\" PY3_DLLNAME, MAXPATHLEN) >= 0) { + if (py3path[0] && _Py_add_relfile(py3path, L"DLLs\\" PY3_DLLNAME L".dll", MAXPATHLEN) >= 0) { hPython3 = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); } } return hPython3 != NULL; #undef MAXPATHLEN +#endif /* PY3_DLLNAME */ +} + +/* To support extensions that can load with both abi3 and abi3t, we also need to + * preload python3t.dll. Due to 3.15 still supporting intermingled layouts, the + * check is a bit more complicated on that version as we need to try loading + * from a subdirectory first in case the adjacent python3t.dll is meant for + * python315t.dll (and we are python315.dll). + */ +static int +_Py_CheckPython3t(void) +{ +#ifndef ABI3T_DLLNAME + return 1; +#else +#if defined(PY3_DLLNAME) && PY_MAJOR_VERSION==3 && PY_MINOR_VERSION==15 + /* GIL-enabled builds of 3.15 might have a python3t.dll adjacent that is for + a free-threaded build. So we first check in a subdirectory in that case. + If it's not there, we'll look adjacent. */ + #define ABI3T_COMPAT_DLLNAME L"abi3t-compat\\" ABI3T_DLLNAME L".dll" +#endif + static int python3t_checked = 0; + static HANDLE hPython3t; + #define MAXPATHLEN 512 + wchar_t py3path[MAXPATHLEN+1]; + if (python3t_checked) { + return hPython3t != NULL; + } + python3t_checked = 1; + + /* If there is a python3t.dll [in the abi3t-compat dir] next to the + python3y.dll, use that DLL */ + if (PyWin_DLLhModule && GetModuleFileNameW(PyWin_DLLhModule, py3path, MAXPATHLEN)) { + wchar_t *p = wcsrchr(py3path, L'\\'); + + if (p) { +#ifdef ABI3T_COMPAT_DLLNAME + wcscpy(p + 1, ABI3T_COMPAT_DLLNAME); + hPython3t = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + if (hPython3t == NULL) +#endif + { + wcscpy(p + 1, ABI3T_DLLNAME L".dll"); + hPython3t = LoadLibraryExW(py3path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + } + if (hPython3t) { + return 1; + } + } + } + + /* If we can locate python3.dll in our application dir, + use that DLL */ +#ifdef ABI3T_COMPAT_DLLNAME + hPython3t = LoadLibraryExW(ABI3T_COMPAT_DLLNAME, NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); + #undef ABI3T_COMPAT_DLLNAME + if (hPython3t == NULL) +#endif + { + hPython3t = LoadLibraryExW(ABI3T_DLLNAME L".dll", NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR); + } + return hPython3t != NULL; + #undef MAXPATHLEN +#endif /* ABI3T_DLLNAME */ } + #endif /* Py_ENABLE_SHARED */ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, @@ -210,6 +281,7 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, #ifdef Py_ENABLE_SHARED _Py_CheckPython3(); + _Py_CheckPython3t(); #endif /* Py_ENABLE_SHARED */ wchar_t *wpathname = PyUnicode_AsWideCharString(pathname, NULL); diff --git a/Tools/msi/common.wxs b/Tools/msi/common.wxs index 54fa749ab17cdd..73da474e4181f1 100644 --- a/Tools/msi/common.wxs +++ b/Tools/msi/common.wxs @@ -75,6 +75,12 @@ + + + + + + diff --git a/Tools/msi/core/core_files.wxs b/Tools/msi/core/core_files.wxs index 145e1471247aa1..8b21501078ea2e 100644 --- a/Tools/msi/core/core_files.wxs +++ b/Tools/msi/core/core_files.wxs @@ -2,6 +2,9 @@ + + + @@ -19,6 +22,9 @@ + + + diff --git a/Tools/msi/freethreaded/freethreaded_files.wxs b/Tools/msi/freethreaded/freethreaded_files.wxs index 0707e77b5e9ab2..fdbcaea38eb317 100644 --- a/Tools/msi/freethreaded/freethreaded_files.wxs +++ b/Tools/msi/freethreaded/freethreaded_files.wxs @@ -29,7 +29,7 @@ - + @@ -37,68 +37,72 @@ - + - + - + - + - + - + + - + - + - + - - + + - + - + - + - + - + - + @@ -111,16 +115,16 @@ - + - + - + @@ -132,16 +136,16 @@ - + - + - + @@ -151,21 +155,21 @@ - + - + - - + + - - + + diff --git a/Tools/msi/msi.props b/Tools/msi/msi.props index 372c4823bce07f..097af60715448f 100644 --- a/Tools/msi/msi.props +++ b/Tools/msi/msi.props @@ -122,6 +122,30 @@ + + + build + + + build + + + build + + + build_t + + + build_t + + + build_t + + src @@ -131,6 +155,7 @@ redist + build32 @@ -140,6 +165,15 @@ buildarm64 + + build32t + + + build64t + + + buildarm64t + diff --git a/Tools/peg_generator/pegen/build.py b/Tools/peg_generator/pegen/build.py index 44a58581686a4f..bc3657067a8da2 100644 --- a/Tools/peg_generator/pegen/build.py +++ b/Tools/peg_generator/pegen/build.py @@ -145,10 +145,15 @@ def compile_c_extension( str(MOD_DIR.parent.parent.parent / "Parser" / "lexer"), str(MOD_DIR.parent.parent.parent / "Parser" / "tokenizer"), ] + library_dirs: list[str] = [] if sys.platform == "win32": # HACK: The location of pyconfig.h has moved within our build, and # setuptools hasn't updated for it yet. So add the path manually for now - include_dirs.append(pathlib.Path(sysconfig.get_config_h_filename()).parent) + include_dirs.append(str(pathlib.Path(sysconfig.get_config_h_filename()).parent)) + if sysconfig.is_python_build(): + # HACK: Our output directory for free-threaded builds has moved, and so + # tests running in-tree require our sys.executable directory for libs + library_dirs.append(str(pathlib.Path(sys.executable).parent)) extension = Extension( extension_name, sources=[generated_source_path], @@ -161,6 +166,7 @@ def compile_c_extension( fixup_build_ext(cmd) cmd.build_lib = str(source_file_path.parent) cmd.include_dirs = include_dirs + cmd.library_dirs = library_dirs if build_dir: cmd.build_temp = build_dir cmd.ensure_finalized()